类似微服务的软件架构,在前端开发中,一个页面的实现往往十分复杂,我们可以将一个页面划分为多个块,每个块负责相应的功能,块之间通过通信来交互。这样的前端开发方式正是组件化开发,一个页面是一个大的组件树,其下又划分有很多小的组件。这样一来,不仅降低了一次开发的难度,而且避免了重复造轮子,组件可以灵活的嵌入其他的Vue项目中进行使用。
Vue.extend()
注册组件:全局/局部
使用组件:Vue实例范围内
Vue.conponent( , )
;
局部:在实例下注册,components: 属性
<script>
var cpnCreater = Vue.extend({
// 反单引号
template: `
<div>
<h2>Vue Component</h2>
</div>
`
});
var vm = new Vue({
el: '#app',
components: {
cpn: cpnCreater
}
});
</script>
components: 属性
,引入子组件,运行时会立刻编译完成。
注意:声明顺序会影响结果。
Vue.extend()
方法,使用对象代替,简化步骤。
<script>
// 全局注册
Vue.component('cpn1', {
template:`
<div>Component1 Test</div>
`
});
var vm = new Vue({
el: '#app',
// 局部组件
components: {
'cpn2': {
template: `
<div>Component2 Test</div>
`}
}
});
</script>
// 使用<script>标签
<script id="cpnDiv" type="text/x-handlebars-template">
// 需要包含一个根
<div>
{{ title }}
Component1 Test
</div>
</script>
// 使用<template>标签
<template id="cpnTemp">
<div>
Component2 Test
</div>
</template>
<script>
// 全局注册
Vue.component('cpn1', {
template: '#cpnDiv',
data() {
title: 'Title'
},
methods: {}
});
</script>
通过props向子组件传递数据
通过事件$emit() + v-on向父组件发送消息
<div :cmovies="movies"></div>
props: ['cmovies', 'cmessage']
// String/Number/Boolean/Array/Object/Date/Function/Symbol
props: {
cmovies: Array,
cmessage: String,
cinfo: {
type: String,
// 类型是对象或数组时,默认值必须是函数,例如:default(){return [];}
default: 'abc',
// required: true
}
}
说明: Vue不支持驼峰命名,需要用-
+小写来代替。
子组件不推荐修改父组件传来的值,应创建一个data进行双向绑定。
// 父传子,其中Vue实例当作父
// props属性
<body>
<div id="app">
<cpn :cmovies="movies"></cpn>
</div>
<template id="cpnTemp">
<div>
<h2>Component2 Test</h2>
<p>{{cmovies}}</p>
<p>{{cmessage}}</p>
</div>
</template>
<script>
// 子组件
const cpn = {
template: '#cpnTemp',
props: {
cmovies: Array,
cmessage: {
type: String,
default: "nothing..."
}
},
data() {
return {}
}
};
var vm = new Vue({
el: '#app',
data: {
message: 'Hi',
movies: ['1', '2', '3']
},
components: {
cpn: cpn
}
});
</script>
</body>
// 子传父
// v-on + v-bind
<body>
<div id="app">
<cpn :cmovies="movies" @item-click="cpnClick"></cpn>
</div>
<template id="cpnTemp">
<div>
<h2>Component2 Test</h2>
<p>{{cmovies}}</p>
<p>{{cmessage}}</p>
<button v-for="item in info" @click="btnClick(item)">{{item.name}}</button>
</div>
</template>
<script>
// 子组件
const cpn = {
template: '#cpnTemp',
props: {
cmovies: Array,
cmessage: {
type: String,
default: "nothing..."
}
},
data() {
return {
info: [
{id: '001', name: 'aaa'},
{id: '002', name: 'bbb'},
{id: '003', name: 'ccc'},
{id: '004', name: 'ddd'},
]
}
},
methods: {
btnClick(item) {
// 自定义事件
this.$emit('item-click', item);
console.log(item);
}
}
};
var vm = new Vue({
el: '#app',
data: {
message: 'Hi',
movies: ['1', '2', '3']
},
components: {
cpn
},
methods: {
cpnClick(item) {
console.log('cpnClick', item);
}
}
});
</script>
</body>
<template></template>
<script></script>
<style></style>
watch: {
_paraName(newValue) {
this._paraName = newValue...;
this.$emit();
}
}
抽取共性,保留不同。
// 多个值会一次性替换
<slot></slot>
// 默认为按钮标签
<slot><button>按钮</button></slot>
v-slot
代替了slot
和scope-slot
。<cpn>
// 组件中使用插槽
<template v-slot="slot1">
<span>It's me!</span>
</template>
</cpn>
// 定义插槽
<template id="cpn">
<div>
<slot name="slot1"></slot>
</div>
</template>
<cpn>
// 组件中访问子组件的message值
<template v-slot="slot1">
<span>{{ slot1.mydata }}</span>
</template>
</cpn>
// 定义插槽,绑定message数据
<template id="cpn">
<div>
<slot name="slot1" :mydata="message"></slot>
</div>
</template>
随着前端代码量的增多,通常会将代码组织在多个js中,进行维护,但这会造成类似全局变量同名、js文件的依赖等问题。
变量名.对象.函数/变量
。
// CommonJS规范的导出
module.exports = { add, mul }
// CommonJS规范的导入
const { add, mul } = require('./xxx.js')
引用<script type="module">
时,js内部的数据都是局部的,无法被其他js文件访问。需要增加export和import关键字。
ES6 export关键字
export {
name, sum
};
export var name = "...";
export function sum(){...};
export class Class{...};
// 只能由一个default
export default age
ES6 import关键字
import {name, sum} from "./xxx.js";
import * as im from "./xxx.js"; // 使用:im.name
// 不需要{},且可以自己命名
import addr from "./xxx.js";