组件化常用技术
组件传值、通信
父组件 => 子组件
1 2 3 4 5 6 7
| props: { msg: String; }
<HelloWorld msg="Welcome to Your Vue.js App" />;
|
1 2 3 4 5 6 7
| // parent <HelloWorld ref="hw" />
this.$refs.hw.xx // P.S. • 如果ref放在了原生DOM元素上,获取的数据就是原生DOM对象 - 可以直接操作 • 如果ref放在了组件对象上,获取的就是组件对象 - 可以获取到组件内data、methods,通过 this.$refs.refName.data名称/method名称 - 可以获取到DOM对象,通过 this.$refs.refName.$el进行操作
|
子组件 => 父组件:自定义事件
1 2 3 4 5 6
| props: { add: Function } this.$emit('add', good)
<Cart @add="cartAdd($event)"></Cart>
|
兄弟组件:通过共同祖辈组件
通过共同的祖辈组件搭桥,$parent
或 $root
。
1 2 3 4 5
| this.$parent.$on('foo', handle);
this.$parent.$emit('foo');
|
祖先和后代之间
- provide/inject:能够实现祖先给后代传值
1 2 3 4 5 6 7
| provide() { return {foo: 'foo'} }
inject: ['foo']
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function dispatch(eventName, data) { let parent = this.$parent while (parent) { parent.$emit(eventName,data) parent = parent.$parent } }
<h1 @click="dispatch('hello', 'hello,world')">{{ msg }}</h1>
this.$on('hello', this.sayHello)
|
任意两个组件之间:事件总线 或 vuex
- 事件总线:创建一个 Bus 类负责事件派发、监听和回调管理
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 44
| 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()
this.$bus.$on('foo', handle)
this.$bus.$emit('foo') copy import Vue from 'vue'; var VueEvent = new Vue(); export default VueEvent;
import VueEvent from '../model/VueEvent.js'; methods: { emitNews() { VueEvent.$emit('to-news', this.msg) } }
import VueEvent from '../model/VueEvent.js'; mounted() { VueEvent.$on('to-news', function(data) {...接收到了data...}) }
|
- Vuex:创建唯一的全局数据管理者 store,通过它管理数据并通知组件状态变更
插槽
Vue 2.6.0 之后采用全新 v-slot 语法取代之前的 slot、slot-scope
匿名插槽
1 2 3 4 5 6 7
| // comp1 <div> <slot></slot> </div>
// parent <comp>hello</comp>
|
具名插槽
1 2 3 4 5 6 7 8 9 10 11 12 13
| // comp2 <div> <slot></slot> <slot name="content"></slot> </div>
// parent <Comp2> <template v-slot:default>具名插槽</template> <template v-slot:content>内容...</template> </Comp2>
|
作用域插槽
1 2 3 4 5 6 7 8 9 10
| // comp3 <div> <slot :foo="foo"></slot> </div>
// parent <Comp3> <template v-slot:default="ctx">来自子组件数据:{{ctx.foo}}</template> </Comp3>
|