目标:
- 深刻理解vue的组件化机制
- 掌握vue组件化常用技术
- 掌握通用组件设计和实现思路
- 加深对vue原理理解
vue组件化是vue的核心思想,极大提高代码复用性、可维护性和可测试性。
资源环境:
- vue-cli 3.x
- node.10.x
- vuejs 2.x
文件目录
App.vue
main.js
parent.vue
child.vue
组件通信
一、父子通信:
1.通过属性传值
<div id="father">
<child v-bind:msg= "message" class="child">
<!-- 通过 v-bind 动态赋值 -->
</child>
</div>
<script>
let father = new Vue({
el:'#father',
components: { child }, // 注册子组件
data: {
message: 'message from father'
}
})
</script>
子组件通过props接收属性
<script>
let child = {
template: `<div>
<p>下面是来自爸爸的信息:</p>
<p>{{ msg }}</p>
</div>`,
props: ['msg']
}
</script>
关于props
- 可以使用v-bind动态绑定父组件来的内容
- 在组件中使用props来从父组件接收参数,注意,在props中定义的属性,都可以在子组件中直接使用
- props来自父级,而组件中data->return的数据就是组件自己的数据,两种情况作用域就是组件本身,可以在template,computed,methods中直接使用
- props的值有两种,一种是字符串数组,一种是对象
- 对于数组或对象类型的 prop来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态(尽可能将父子组件解耦,避免子组件无意中修改了父组件的状态),不介意直接修改prop的数据。
除去props传递,对于标签的原生API可以使用 $attrs 传递
$attrs--继承所有的父组件属性(除了prop传递的属性、class 和 style )
inheritAttrs:默认值true,继承所有的父组件属性(除props的特定绑定)作为普通的HTML特性应用在子组件的根元素上,如果你不希望组件的根元素继承特性设置inheritAttrs: false,但是class属性会继承 代码示例:
<div id="app">
<base-input label="姓名" class="username-input" placeholder="username" data-date-picker="activated"></base-input>
</div>
<script>
Vue.component("base-input", {
inheritAttrs: false, //此处设置禁用继承特性
props: ["label"],
template: `
<label>
{{label}}
{{$attrs.placeholder}}
{{$attrs["data-date-picker"]}}
<input v-bind="$attrs"/>
</label>
`,
mounted: function() {
console.log(this.$attrs);
}
})
const app = new Vue({
el: '#app',
data: {}
});
</script>


2.通过ref 引用
<child v-bind:msg="message" class="child" ref="parent">
<script>
let father = new Vue({
el:'#father',
components: { child }, // 注册子组件
data: {
message: 'message from father'
},
mounted () {
console.log(this.$refs.parent.msg)
}
})
</script>
3.通过children:不保证children中的属性顺序
<child v-bind:msg="message" class="child" ref="parent">
<script>
let father = new Vue({
el:'#father',
components: { child }, // 注册子组件
data: {
message: 'message from father'
},
mounted () {
console.log(this.$children[0].msg)
}
})
</script>
二、子父通信:
1.通过事件派发:
<script>
let child = {
template: `<div>
<p>下面是来自爸爸的信息:</p>
<p>{{ msg }}</p>
<h1 @click="$emit('foo', 'hello123')">123</h1>
</div>`,
props: ['msg']
}
</script>
父接收:
<child v-bind:msg= "message" class="child" @foo="onfoo"> </child>
<script>
let father = new Vue({
el:'#father',
components: { child }, // 注册子组件
data: {
message: 'message from father'
},
methods: {
onfoo (data) {
console.log('子给父' + data)
}
}
})
</script>
三、兄弟通信:
1.中间人桥接(parent,root)
<button @click="message">兄弟组件</button>
mounted () {
this.$parent.$on('foo', () => {
console.log('兄弟组件测试')
})
},
methods: {
message () {
this.$parent.$emit('foo')
}
}
现象: 点击一个button,却触发两次

缺点:耦合度高,监听需要做过滤处理
2.总线模式bus
main.js或公共方法js文件中:
class Bus {
constructor () {
this.callbacks = {}
}
$on (name, fn) {
this.callbacks[name] = this.callbacks[name] || []
this.callbacks[name].push(fn)
}
$emit (name, args) {
if (this.callbacks[name]) {
this.callbacks[name].forEach(cb => cb(args))
}
}
}
Vue.prototype.$bus = new Bus()
// Vue.prototype.$bus = new Vue()
可以用Vue()原因:Vue本身就有on和emit
mounted () {
this.$bus.$on('foo', () => {
console.log('兄弟组件bus测试')
})
},
methods: {
message () {
this.$bus.$emit('foo')
}
}
3.vuex(后期单独补充说明)
四、祖代通信:(跨层级传参)
祖代传参通过provide:(provide的参数不建议修改)
let father = new Vue({
el:'#father',
components: { child }, // 注册子组件
provide () {
return {
'foo': 'provide testData'
}
},
data: {
message: 'message from father'
},
methods: {
onfoo (data) {
console.log('子给父' + data)
}
}
})
子代接收通过inject:
let child = {
template: `<div>
<p>下面是来自爸爸的信息:</p>
<p>{{ msg }}</p>
<p>下面是来自祖代的信息:</p>
<p>{{foo}}</p>
</div>`,
props: ['msg'],
inject: ['foo']
}
五、毫无关系
vuex(后期单独补充说明)