[TOC] ## :-: vue - 自定义组件(全局/局部) ``` <div id="app"> <!-- 自定义组件 --> <demo-name /> <e-name /> </div> <script> // 自定义组件(全局/局部) // 定义全局组件 Vue.component('eName', { template: '<div>{{msg}}</div>', data() { return { msg: 'Hello World ~' } }, }); // 定义局部组件 const oVue = new Vue({ el: '#app', data: { test: '123' }, components: { DemoName: { template: '<p>{{msg}}</p>', data() { return { msg: '--------------' } }, } } }); </script> ``` ## :-: vue - 组件数据传递/属性校验 ``` <div id="app"> <!-- 自定义组件 --> <my-content a="aaa" b="bbb" :title="title" :content="content"></my-content> </div> <script> // 组件数据传递/属性校验 const oVue = new Vue({ el: '#app', data: { title: '我是标题', content: '我是内容区域' }, components: { myContent: { // props -- 注册属性(传递数据) props: { // 属性校验(规定数据类型、是否必填以及默认值) content: { // 类型 type: String, // 是否必须 required: true, // 默认值 如果是引用值需要写成函数返回的形式 ()=>[1,2,3] default: '默认内容' }, title: { // 类型 type: Number, // 是否必须 required: true, // 校验数据 validator(value) { return value >= 10; // true/false } } }, // props: ['a', 'b', 'title', 'content'], // 简写 // template -- 生成模版 template: `<div> <h1>{{title}}</h1> <p>{{content}}</p> <p>--- <span>{{a}}</span> --- <span>{{b}}</span> ---</p> </div>` } } }); </script> ``` ## :-: vue - 组件数据交互(1) ``` <div id="app"> <!-- 自定义组件 --> <my-content></my-content> </div> <script> // 组件数据交互 const oVue = new Vue({ el: '#app', data: { title: '标题', content: '内容', }, comments: { // props: ['title'], // 使用 this.$parent 可以不用注册、 // 创建后 created() { // this.$attrs -- 未注册的属性列表、 console.log(this.$attrs); // this.$parent -- 可以拿到实例上的数据(父组件)、 console.log(this.$parent); this.title = this.$parent.title; }, // 挂在后 mounted() { // this.$childen -- 在父组件中可以拿到子组件的数据、 console.log(this.$childen); }, // v-bind="$attrs" -- this.$attrs -- 未注册的属性列表、 template: `<div> <h3>{{ title }}</h3> <my-p v-bind="$attrs"></my-p> // this.$attrs 属性及内容会显示在行间上、 <my-p></my-p> -- // this.$parent </div>>`, // 防止 v-bind="$attrs" 时属性显示在行间上 inheritAttrs: false, comments: { myP: { // props: ['content'], // 使用 this.$parent 可以不用注册、 created() { this.content = this.$parent.$parent.content; }, template: `<p>{{ content }}</p>` } } } }); </script> ``` ``` <div id="app"> <!-- 自定义组件 --> <my-content></my-content> </div> <script> // 组件数据交互 const oVue = new Vue({ el: '#app', // 提供数据 provide: { title: '标题', content: '内容', }, components: { myContent: { // 注入数据 inject: ['title'], template: `<div> <h3>{{title}}</h3> <my-p></my-p> </div>`, components: { myP: { // 注入数据 inject: ['content'], template: `<p>{{ content }}</p>` } } } } }); </script> ``` ## :-: vue - 组件数据交互(2) ``` <div id="app"> <!-- ref="myDom" -- 给dom设置引用 --> <div ref="myDom"></div> <!-- 自定义组件 --> <!-- ref="myCmp" -- 可以拿到这个组件的实例 --> <my-content ref="myCmp" :func1="func"></my-content> <!-- native -- 自定义组件不能绑定事件,需要通过修饰符修饰后才可以 --> <my-test @click.native="myClick"></my-test> <my-test @click="myClick" :test="test"></my-test> </div> <script> // 组件数据交互 const oVue = new Vue({ el: '#app', data: { test: 123 }, mounted() { // this.$refs -- 引用 console.log(this.$refs.myDom); // 返回:div 的 dom 对象、 console.log(this.$refs.myCmp); // 返回:自定义组件(myContent)的实例对象、 this.$refs.myCmp.cmpFunc(); }, methods: { func(data) { console.log(data); }, myClick(e) { console.log('myClick', e); } }, components: { myContent: { props: ['func1'], data() { return { msg: 'Hello World' } }, methods: { cmpFunc() { console.log('cmp'); }, clickFun() { this.func1(this.msg); // props:['func1'] }, }, template: `<button @click="clickFun">{{ msg }}</button>` }, myTest: { // template: '<button @click="handleClick">Yes</button>', template: '<button v-on="$listeners">Yes</button>', methods: { handleClick() { // this.$attrs -- 可以拿到行间上面的属性数据、 console.log(this.$attrs); // this.$listeners -- 可以拿到行间上所有通过v-on绑定的方法、 console.log(this.$listeners); this.$listeners.click(); // @click="handleClick" // 主动触发一个事件 this.$emit('click', '传递的数据'); }, }, } } }); </script> ``` ## :-: vue - 组件数据交互(3) ``` <div id="app"> <!-- 自定义组件 --> <my-input></my-input> <my-content></my-content> </div> <script> // event bus -- 事件总线 (子级中兄弟组件间的通讯) // 在原型链中扩展一个方法,用于存在数据的介质、Vue.prototype.bus = new Vue(); Vue.prototype.bus = new Vue(); const oVue = new Vue({ el: '#app', data: { test: 'abc' }, components: { // -- 自定义组件A myContent: { template: '<div>{{ content }}</div>', data() { return { content: '' } }, created() { // $on -- 监听事件 this.bus.$on('click', val => { this.content = val; console.log('-->', val); }); }, }, // -- 自定义组件B myInput: { data() { return { inputVal: '' } }, methods: { handleClick() { // $emit -- 触发事件 this.bus.$emit('click', this.inputVal); } }, template: `<div> <input type="text" v-model='inputVal'> <button @click="handleClick">提交</button> </div>` } } }); </script> ``` ## :-: vue - 组件·单向通信 ``` <div id="app"> <!-- 自定义组件 --> <my-count :obj="countObj"></my-count> </div> <script> function copyObj(data) { // 克隆对象、 let json = JSON.stringify(data); return JSON.parse(json); } // 组件间单向通信 Vue.component('myCount', { props: ['obj'], template: `<p>{{ myObj.a }}</p>`, data() { return { // 在组件中 this 不为 window ,所以可以直接赋值、 myObj: copyObj(this.obj), // 将全局变量赋值到局部、避免污染全局 } }, mounted() { setInterval(() => { this.myObj.a++; }, 500); }, }) const oVue = new Vue({ el: '#app', data: { countObj: { a: 10 } }, }); </script> ``` ## :-: vue - 组件·双向通信 ``` <div id="app"> <!-- 自定义组件 --> <!-- @input="func" -- 捕获自定义事件、(接收子组件传过来的值) --> <my-count :count="count" @input="func"></my-count> </div> <script> // 组件间双向通信 Vue.component('myCount', { props: ['count'], template: `<p>{{ myCount }}</p>`, data() { return { // 在组件中 this 不为 window ,所以可以直接赋值、 myCount: this.count, // 将全局变量赋值到局部、避免污染全局 } }, mounted() { setInterval(() => { // this.$emit -- 触发自定义事件、 this.$emit('input', ++this.myCount); }, 500); }, }) const oVue = new Vue({ el: '#app', data: { count: 100 }, methods: { // @input="func" -- 捕获自定义事件、(接收子组件传过来的值) func(val) { this.count = val; } }, }); </script> ``` ``` <div id="app"> <!-- 自定义组件 --> <!-- 简写: :value + @input = v-model --> <my-count v-model="count"></my-count> </div> <script> // 组件间双向通信 (简写) Vue.component('myCount', { props: ['value'], template: `<p>{{ value }}</p>`, mounted() { setInterval(() => { let value = this.value + 1; // this.$emit -- 触发自定义事件、 this.$emit('input', value); }, 500); }, }) const oVue = new Vue({ el: '#app', data: { count: 100 } }); </script> ``` ## :-: vue - 插槽(slot) ``` <div id="app"> <my-but>插槽</my-but> </div> <script> Vue.component('myBut', { template: `<button><slot></slot></button>` }); new Vue({ el: '#app' }); </script> ``` ``` <div id="app"> <my-test> <template v-slot:top>标题</template> <!-- v-slot: 简写:# --> <template #bottom>正文</template> </my-test> </div> <script> new Vue({ el: '#app', components: { myTest: { template: `<div> <h1><slot name='top'></slot></h1> <h3><slot name='bottom'></slot></h3> </div>`, } } }); </script> ```