父子组件间的数据传递
- 父组件通过属性的形式(v-bind:[xxx])向子组件传递数据
- 子组件通过事件触发的形式向父组件传值
- 单项数据流:父组件可以向子组件传递任意数据,但是子组件不能修改传递过来的数据(clone一份使用),因为如果是引用类型的数据,更改会影响其他子组件的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| <div id="root"> <counter :count="123" @inc="handleIncrease"></counter> <counter :count="1" @inc="handleIncrease"></counter> <div>{{total}}</div> </div> ``` ```js let counter = { props: ['count'], data: function () { return { // 传递过来的参数不能直接修改,而是要clone一份自己使用 number: this.count } }, template: '<div @click="handleClick">{{number}}</div>', methods: {
handleClick() { // 单项数据流,子组件不能改父组件传来的数据,因为引用类型的数据,改了会影响其他子组件 // this.count++ this.number++ // 子组件通过事件触发的形式向组件传值 this.$emit('inc', 1) // 单向数据流, 父组件可以向子组件传递任意数据,但是子组件不能修改子组件传递来的数据 } } } let vm = new Vue({ el: '#root', data: { total: 124 }, components: { counter: counter }, methods: { handleIncrease(step) { this.total += step } } })
|
组件参数校验与非props特性
props特性
- 父组件传递的属性不会再dom上显示
- 子组件可以接收和直接在组件中使用传递过来的属性(如本例中content)
非props特性
子组件内部并没有声明父组件要传递的属性
- 非props,属性会展示在最外层dom标签中
- 在子组件中没办法获取到内容,因为没有声明
参数校验
props传递的参数,在子组件内部可以用对象的形式对参数进行校验
1 2 3 4
| <div id="root"> <child content="haha"></child> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| Vue.component('child', { props: { content: { type: String, required: false, default: 'default value', validator: function (value) { return (value.length > 5) } } }, template: '<div>{{content}}</div>' })
let vm = new Vue({ el: '#root', data: {
}, methods: {
} })
|
给组件绑定原生事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <div id="root"> <child @click="handleClick"></child> <child @click.native="handleClick"></child> </div> <script> Vue.component('child', { template: '<div @click="handleChildClick">Child</div>', methods: { handleChildClick() { this.$emit('click') } } })
let vm = new Vue({ el: "#root", data: {
}, methods: { handleClick() { alert('click') } } }) </script>
|
非父子组件间的传值
- Vuex解决
- 总线机制(Bus/总线/发布订阅模式/观察者模式)
1 2 3 4
| <div id="root"> <child content="Dell"></child> <child content="Lee"></child> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
Vue.prototype.bus = new Vue()
Vue.component('child', { data: function () { return { selfContent: this.content } }, props: { content: String }, template: '<div @click="handleClick">{{selfContent}}</div>', methods: { handleClick() { this.bus.$emit('change', this.selfContent) } }, mounted: function () { let _this = this this.bus.$on('change', function (msg) { _this.selfContent = msg }) } })
let vm = new Vue({ el: '#root', methods: {
} })
|
在vue中使用插槽slot
slot基本用法
- 当子组件中有一部分内容需要根据父组件的dom传递过来的时候
- 父组件向子组件优雅的传递dom–slot
- slot可以设置默认内容
1 2 3 4 5 6
| <div id="root"> <child> <p>Dell</p> </child> </div>
|
1 2 3 4 5 6 7 8 9 10
| Vue.component('child', { template: `<div> <p>hello</p> <slot>默认内容</slot> </div>` })
let vm = new Vue({ el: '#root' })
|
具名插槽slot
- 子组件中
<slot name=header>
- 父组件中
<div class="header" slot="header">header</div>
,
1 2 3 4 5 6 7
| <div id="root"> <body-content> <div class="header" slot="header">header</div> <div class="footer" slot="footer">footer</div> </body-content> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| Vue.component('body-content', { template: ` <div> <slot name="header"> <h1>default header</h1> </slot> <div class="content">content</div> <slot name="footer"></slot> </div>` })
let vm = new Vue({ el: '#root' })
|
作用域插槽
1 2 3 4 5 6 7 8 9 10 11
| <div id="root"> <child> <template slot-scope="props"> <li>{{props.item}}</li> </template> </child> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Vue.component('child', { data: function () { return { list: [1,2,3,4] } }, template: `<div> <ul> <slot v-for="item of list" :item=item> </slot> </ul> </div>` })
let vm = new Vue({ el: '#root', })
|
Vue中的动态组件与v-once指令
<component :is="type"></component>
:is
标记使用哪个组件
v-once
表示缓存组件,不用每次销毁重建
1 2 3 4 5 6 7
| <div id="root">
<component :is="type"></component> <button @click="handleBtnClick">change</button> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| Vue.component('child-one', { template: '<div v-once>child-one</div>' })
Vue.component('child-two', { template: '<div v-once>child-two</div>' })
let vm = new Vue({ el: '#root', data: { type: 'child-one' }, methods: { handleBtnClick() { this.type = (this.type === 'child-one' ? 'child-two' : 'child-one') } } })
|