Vue组件化开发 ->(个人学习记录笔记)

  • A+
所属分类:Web前端
摘要

@props数据验证自定义事件

@

Vue

1. 组件化开发

1.1 基本使用过程

  • 注册组件的基本步骤:
    • 创建组件
    • 注册组件
    • 使用组件

  • Vue.extend():
    • 调用Vue.extend()创建的是一个组件构造器。
    • 通常在创建组件构造器时,传入template代表我们自定义组件的模板
    • 改模板就是在使用到组件的地方,要显示的HTML代码
  • Vue.component():
    • 调用Vue.component()是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称
    • 所以需要传递两个参数:1、注册组件的标签名 2、组件构造器
  • 组件必须挂载在某个Vue实例下。否则他不会生效

Vue组件化开发 ->(个人学习记录笔记)

<div id="app">   <!-- 3.使用组件 -->   <my-cpn></my-cpn>   <my-cpn></my-cpn>   <my-cpn></my-cpn>   <my-cpn></my-cpn>   <my-cpn></my-cpn> </div> <script src="../js/vue.js"></script> <script>   //1.创建爱你组件构造器对象   const cpnC = Vue.extend({     template: `         <div>           <h2>我是标题</h2>           <p>我是内容,哈哈哈</p>           <p>我是内容,呵呵呵</p>         </div>`   })   //2.注册组件   Vue.component('my-cpn', cpnC);      const app = new Vue({     el: '#app',     data: {       message: '你好啊!'     }   }) </script> 

1.2 全局组件和局部组件

  • 全局组件:在Vue实例外注册,可以在多个Vue的实例下使用
  • 局部组件:在Vue实例内注册,可以在其Vue的实例下使用
<div id="app2">   <cpn></cpn> </div> <div id="app">   <!-- 3.使用组件 -->   <cpn></cpn>   <cpn></cpn> </div> <script src="../js/vue.js"></script> <script>   //1.创建爱你组件构造器对象   const cpnC = Vue.extend({     template: `         <div>           <h2>我是标题</h2>           <p>我是内容,哈哈哈</p>         </div>`   })   //2.注册组件(全局组件,意味着可以在多个Vue的实例下使用)   // Vue.component('cpn', cpnC);    const app = new Vue({     el: '#app',     data: {       message: '你好啊!'     },     components:{       //cpn 使用组件时的标签名(局部组件)       cpn:cpnC     }   })   const app2 = new Vue({     el: '#app2'   }) </script> 

1.3 父组件和子组件

<div id="app">   <cpn2></cpn2> </div> <script src="../js/vue.js"></script> <script>   //1. 创建第一个组件   const cpnC1 = Vue.extend({     template: `       <div>         <h2>我是标题1</h2>         <p>我是内容1</p>       </div>     `   })    //2. 创建第二个组件   const cpnC2 = Vue.extend({     template: `       <div>         <h2>我是标题2</h2>         <p>我是内容2</p>         <cpn1></cpn1>       </div>`,     components:{       cpn1:cpnC1     }   })    const app = new Vue({     el: '#app',     data: {       message: '你好啊!'     },     components:{       cpn2:cpnC2     }   }) </script> 

1.4 注册组件的语法糖写法

  • 省去Vue.extend()
<div id="app">   <cpn1></cpn1>   <cpn2></cpn2> </div> <script src="../js/vue.js"></script> <script>   // 1. 全局组件注册的语法糖   // 1. 创建组件构造器   // const cpn1 = Vue.extend()   // 2. 注册组件   //全局组件   Vue.component('cpn1',{     template: `       <div>         <h2>我是标题1</h2>         <p>我是内容1</p>       </div>     `   });    const app = new Vue({     el: '#app',     data: {       message: '你好啊!'     },     //注册局部组件的语法糖     components:{       'cpn2':{           template: `             <div>               <h2>我是标题2</h2>               <p>我是内容2</p>             </div>           `       }     }   }) </script> 

Vue组件化开发 ->(个人学习记录笔记)

1.5 组件模板抽离

  • script标签
  • template标签
<div id="app"> <cpn></cpn> <cpn></cpn> <cpn></cpn> </div> <!--1. script标签,注意:类型必须是text/x-template--> <script type="text/x-template" id="cpn">   <div>     <h2>我是标题2</h2>     <p>我是内容2</p>   </div> </script> <!--2.template标签--> <template id="cpn1">   <div>     <h2>我是标题2</h2>     <p>我是内容2</p>   </div> </template> <script src="../js/vue.js"></script> <script>    //1.注册一个组件   Vue.component('cpn',{     template: '#cpn1'   })    const app = new Vue({     el: '#app',     data: {       message: '你好啊!'     }   }) </script> 

1.6 组件中的data

<div id="app">   <cpn></cpn> </div> <template id="cpn">   <div>     <h2>{{counter}}</h2>     <button @click="increment">+</button>     <button @click="decrement">-</button>   </div> </template> <script src="../js/vue.js"></script> <script>   Vue.component('cpn',{     template: '#cpn',     data(){       return{         counter:0       }     },     methods:{       increment(){         this.counter++;       },       decrement(){         this.counter--;       }     }   })   const app = new Vue({     el: '#app',     data: {       message: '你好啊!'     }   }) </script> 

1.7 父子组件通信

父传子

  • 方法
    • 通过props向子组件传递数据
    • 通过事件向父组件发送消息
      Vue组件化开发 ->(个人学习记录笔记)
  • Vue实例和子组件的通信 和 父组件和子组件的通信过程是一样的
props
  • 不要用驼峰标识 v-bind无法识别,如必须使用:c-info="info" 组件内用驼峰cInfo
  • 在组件中,使用选项props来声明需要从父级接收到的数据。
  • props的值有两种方式:
    • 方式一:字符串数组,数组中的字符串就是传递时的名称
    • 方式二:对象,对象可以设置传递时的类型,也可以设置默认值等

props数据验证

  • 支持的类型
    • String
    • Number
    • Boolean
    • Array
    • Object
    • Date
    • Function
    • Symbol
<div id="app">   <cpn :cmovies="movies" :cmessage="message"></cpn> </div> <template id="cpn">   <div>     <ul>       <li v-for="item in cmovies">{{item}}</li>     </ul>     <h2>{{cmessage}}</h2>   </div> </template> <script src="../js/vue.js"></script> <script>   //父传子 props   const cpn = {     template: '#cpn',     // props: ['cmovies','cmessage'],     props:{       //1.类型限制       // cmovies: Array,       // cmessage: String,        //2.提供一些默认值       cmessage: {         type: String, //类型         default:'aaaaa',  //默认值         required: true       },       //类型是对象或者数组时,默认值必须是一个函数       cmovies: {         type:Array,         default() {           return []         }       }     },     data(){       return{}     },   }    const app = new Vue({     el: '#app',     data: {       message: '你好啊!',       movies:['海王','海贼王','海尔兄弟']     },     components:{       cpn,     }   }) </script> 

子传父

自定义事件

  • $emit
<!--父组件模板--> <div id="app">   <cpn @item-click="cpnClick"></cpn> </div>  <!--子组件模板--> <template id="cpn">   <div>     <button v-for="item in categories" @click="itemClick(item)">       {{item.name}}     </button>   </div> </template> <script src="../js/vue.js"></script> <script>   //子组件   const cpn = {     template: '#cpn',     data() {       return {         categories: [           {id: 'aaa', name: '热门推荐'},           {id: 'bbb', name: '手机数码'},           {id: 'ccc', name: '家用家电'},           {id: 'ddd', name: '电脑办公'},         ]       }     },     methods: {       itemClick(item) {         this.$emit('item-click',item)         // console.log(item);       }     }   }    //父组件   const app = new Vue({     el: '#app',     data: {       message: '你好啊!',       movies: ['海王', '海贼王', '海尔兄弟']     },     components: {       cpn,     },     methods: {       cpnClick(item){         console.log('aaaaa',item);       }     }   }) </script> 

父子组件通信案例

<div id="app">   <cpn :number1="num1"        :number2="num2"        @num1change="num1change"        @num2change="num2change"></cpn> </div>  <template id="cpn">   <div>     <h2>props:{{number1}}</h2>     <h2>data:{{dnumber1}}</h2> <!--    <input type="text" v-model="dnumber1">-->     <input type="text" :value="dnumber1" @input="num1Input">     <h2>props:{{number2}}</h2>     <h2>data:{{dnumber2}}</h2> <!--    <input type="text" v-model="dnumber2">-->     <input type="text" :value="dnumber2" @input="num2Input">   </div> </template> <script src="../js/vue.js"></script> <script>   const app = new Vue({     el: '#app',     data: {       message: '你好啊!',       num1:1,       num2:0     },     methods: {       num1change(value){         this.num1=parseInt(value);       },       num2change(value){         this.num2=parseInt(value);       }     },     components:{       cpn:{         template:'#cpn',         props:{           number1:Number,           number2:Number         },         data(){           return {             dnumber1:this.number1,             dnumber2:this.number2,           }         },         methods:{           num1Input(event){             this.dnumber1=event.target.value;             this.$emit('num1change', this.dnumber1);              this.dnumber2 = this.dnumber1*100;             this.$emit('num2change',this.dnumber2);           },           num2Input(event){             this.dnumber2=event.target.value;             this.$emit('num2change', this.dnumber2);              this.dnumber1 = this.dnumber2/100;             this.$emit('num1change',this.dnumber1)           },         }       }     },    }) </script> 

watch监听改变

 watch:{           dnumber1(newValue){             this.dnumber2 =  newValue*100;             this.$emit('num1change', newValue);           },           dnumber2(newValue){             this.dnumber1 =  newValue*100;             this.$emit('num2change', newValue);           }         }, 

父子组件的访问方式: $children

  • 父组件访问子组件:使用$children$refs(引用)
  • 子组件访问父组件:使用$parent
父访问子
<div id="app">   <cpn></cpn>   <cpn></cpn>   <cpn ref="aaa"></cpn>   <button @click="btnClick">按钮</button> </div> <template id="cpn">   <div>我是子组件</div> </template> <script src="../js/vue.js"></script> <script>   const app = new Vue({     el: '#app',     data: {       message: '你好啊!'     },     methods: {       btnClick(){         //1.关于$children         // console.log(this.$children);         // for(let c of this.$children){         //   console.log(c.name);         //   c.showMessage();         // }          //2.$refs         console.log(this.$refs);        }     },     components:{       cpn:{         template:'#cpn',         data() {           return{             name: '我是子组件的name'           }         },         methods:{           showMessage(){             console.log('showMessage');           }         }       }     }   }) </script> 
子访问父
<div id="app">   <cpn></cpn> </div> <template id="cpn">   <div>     <h2>我是cpn组件</h2>     <ccpn></ccpn>   </div> </template> <template id="ccpn">   <div>     <h2>我是子组件</h2>     <button @click="btnClick">按钮</button>   </div> </template> <script src="../js/vue.js"></script> <script>   const app = new Vue({     el: '#app',     data: {       message: '你好啊!'     },     components:{       cpn:{         template:'#cpn',         data(){           return{             name:'我的cpn组件的name'           }         },         components: {           ccpn:{             template:'#ccpn',             methods:{               btnClick(){                 //1.访问父组件                 console.log(this.$parent);                 console.log(this.$parent.name);                  //2.访问根组件$root                 console.log(this.$root);                 console.log(this.$root.message);               }             },           }         }       }     }   }) </script> 

2. 组件化高级

2.1 slot 插槽

2.1.1 基本使用

  1. 插槽的基本使用<slot></slot>
  2. 插槽的默认值<slot>button</slot>
  3. 多个值同时放入到组件中,则一起组我诶替换元素
<!--1. 插槽的基本使用<slot></slot>--> <!--2. 插槽的默认值<slot>button</slot>--> <!--3. 多个值同时放入到组件中,则一起组我诶替换元素--> <div id="app">   <cpn>     <button>案例</button>   </cpn>   <cpn>     <span>哈哈哈</span>   </cpn>   <cpn>     <i>哈哈哈</i>     <div>我是div元素</div>     <p>我是p元素</p></cpn>   <cpn>     <button>新按钮</button>   </cpn>   <cpn></cpn> </div> <template id="cpn">   <div>     <h2>我是组件</h2>     <p>我是组件,哈哈哈</p>     <!--设置默认值-->     <slot>       <button>默认按钮</button>     </slot>   </div> </template> <script src="../js/vue.js"></script> <script>   const app = new Vue({     el: '#app',     data: {       message: '你好啊!'     },     components: {       cpn: {         template: '#cpn',       }     }   }) </script> 

2.1.2 具名插槽

  • 多个插槽,区分通过添加name
<div id="app">   <cpn>     <button slot="left">返回</button>     <span slot="center">标题</span>   </cpn> </div> <template id="cpn">   <div>     <slot name="left"><span>左边</span></slot>     <slot name="center"><span>中间</span></slot>     <slot name="right"><span>右边</span></slot>   </div> </template> <script src="../js/vue.js"></script> <script>   const app = new Vue({     el: '#app',     data: {       message: '你好啊!'     },     components:{       cpn:{         template:'#cpn'       }     }   }) </script> 

2.2 编译作用域

<div id="app">   <cpn v-show="isShow"></cpn> </div> <template id="cpn">   <div>     <h2>我是子组件</h2>     <p>我是内容,哈哈哈</p>     <button v-show="isShow">按钮</button>   </div> </template> <script src="../js/vue.js"></script> <script>   const app = new Vue({     el: '#app',     data: {       message: '你好啊!',       isShow:true     },     components:{       cpn:{         template:'#cpn',         data(){           return{             isShow: true           }         }       }     }   }) </script> 

2.3 作用域插槽

<div id="app">   <cpn></cpn>   <cpn>     <!--<span v-for="item in pLanguages"></span>-->     <template slot-scope="slot"> <!--      <span v-for="item in slot.data"> {{item}}- </span>-->       <span>{{slot.data.join(' - ')}}</span>     </template>   </cpn>    <cpn>     <!--<span v-for="item in pLanguages"></span>-->     <template slot-scope="slot"> <!--      <span v-for="item in slot.data"> {{item}}* </span>-->       <span>{{slot.data.join(' * ')}}</span>     </template>   </cpn> </div> <template id="cpn">   <div>     <slot :data="pLanguages">       <ul>         <li v-for="item in pLanguages">{{item}}</li>       </ul>     </slot>   </div> </template> <script src="../js/vue.js"></script> <script>   const app = new Vue({     el: '#app',     data: {       message: '你好啊!'     },     components:{       cpn:{         template:"#cpn",         data(){           return{             pLanguages:['JavaScript','C++','Java','C#','Python','Go','Swift']           }         }       }     }   }) </script> 

Vue组件化开发 ->(个人学习记录笔记)