全局组件的使用
//1 创建组件构造器对象 const cpnContructor = Vue.extend({ template:` <div> <h2>我是标题</h2> <p>我是内容</p> </div>` }) //2 注册组件 Vue.component('my-cpn',cpnContructor) const app = new Vue({ el:"#app" })
<div id="app"> <my-cpn></my-cpn> <my-cpn></my-cpn> </div>
全局组件,意味着可以在多个Vue实例下面使用
局部组件
只能在单个实例里使用
<body> <div id="app"> <cpn></cpn> </div> </body> <script> //1 创建组件构造器对象 const cpnContructor = Vue.extend({ template:` <div> <h2>我是标题</h2> <p>我是内容</p> </div>` }) //2 注册组件(全局组件,意味着可以在多个Vue实例下面使用) //Vue.component('my-cpn',cpnContructor) const app = new Vue({ el:"#app", components:{ //使用组件时的标签名:组件构造器 cpn:cpnContructor } }) </script>
const app = new Vue({ el:"#app", components:{ //使用组件时的标签名:组件构造器 cpn:cpnContructor } })
父组件与子组件
<body> <div id="app"> <cpn2></cpn2> </div> </body> <script> //1 创建第一个组件构造器(子组件) const cpnC1 = Vue.extend({ template:` <div> <h2>我是标题1</h2> <p>我是内容 哈哈哈</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", components:{ //使用组件时的标签名:组件构造器 cpn2:cpnC2 } }) </script>
组件的语法糖注册方式
主要省去了Vue.extend()的步骤,可以直接使用一个对象代替
<body> <div id="app"> <cpn1></cpn1> <cpn2></cpn2> </div> </body> <script> const cpn1 = { template:` <div> <h2>我是标题1</h2> <p>我是全局组件的语法糖</p> </div> ` } const cpn2 = { template:` <div> <h2>我是标题2</h2> <p>我是局部组件的语法糖</p> </div> ` } Vue.component('cpn1',cpn1) //注册全局组件语法糖的写法 const app = new Vue({ el:"#app", components:{ //注册局部组件的语法糖 'cpn2':cpn2 } }) </script>
模板分离写法(推荐)
<body> <div id="app"> <cpn1></cpn1> <cpn2></cpn2> </div> </body> <script type="text/x-template" id='cpn1'> <div> <h2>我是标题1</h2> <p>text/x-template写法</p> </div> </script> <template id='cpn2'> <div> <h2>我是标题2</h2> <p>template标签写法</p> </div> </template> <script> //Vue.component('cpn',cpn) //注册全局组件语法糖的写法 Vue.component('cpn1',{ template:"#cpn1" }) const app = new Vue({ el:"#app", components:{ //注册局部组件 'cpn2':{template:"#cpn2"} } }) </script>
组件的data赋值
<body> <div id="app"> <cpn1></cpn1> <cpn2></cpn2> </div> </body> <script type="text/x-template" id='cpn1'> <div> <h2>我是标题1{{title}}</h2> <p>text/x-template写法</p> </div> </script> <template id='cpn2'> <div> <h2>我是标题2</h2> <p>template标签写法</p> </div> </template> <script> //Vue.component('cpn',cpn) //注册全局组件语法糖的写法 Vue.component('cpn1',{ template:"#cpn1", data(){ return { title:'我是组件里的{{动态数据 必须是函数 返回动态对象' } } }) const app = new Vue({ el:"#app", components:{ //注册局部组件 'cpn2':{template:"#cpn2"} } }) </script>
为什么数组data必须是函数
··1、
data:{ counter:0 },
直接报错
the "data" option should be a function that returns a per-instance value in component definitions.
2、
const obj = { counter:0 } Vue.component('cpn1',{ template:"#cpn1", data:{ counter:0 }, data(){ return obj }, methods:{ increment(){ this.counter++ }, decrement(){ this.counter-- } } })
组件调用三次,数据共享 引起连锁反应
3 函数式返回
组件里的data必须是函数
data(){//创建新的函数对象在不同的内存栈空间里 return { counter: 0 } },
父子组件通信
props 从父组件-——》子组件的数据
props的值有两种方式:
方式1 :字符串数据,数组中的字符串就说传递时的名称
<body> <div id="app"> 把变量movies(['海王','海贼王','海尔兄弟']) 当做字符串 传递到子组件 <cpn v-bind:cmovies='movies' :cmessage='message'> </cpn> </div> </body> <template id='cpn'> <div> <h2>{{cmovies}}</h2> <ul> <li v-for='cmovie in cmovies'>{{cmovie}}</li> </ul> <p>{{cmessage}}</p> </div> </template> <script> const cpn = { template:'#cpn', props:['cmovies','cmessage'], data(){ return {} } } const app = new Vue({ el:"#app", data:{ message:'你好啊', movies:['海王','海贼王','海尔兄弟'] }, components:{ cpn //相当于cpn:cpn } }) </script>
方式2:对象。对象可以设置传递时的类型,也可以设置默认值等。
props数据验证
验证都支持哪些类型呢
Srting
Number
boolean
Array
Object
Date
Function
Symbol
<body> <div id="app"> 把变量movies(['海王','海贼王','海尔兄弟']) 当做字符串 传递到子组件 <!-- <cpn v-bind:cmovies='movies' :cmessage='message'> </cpn>--> <cpn > </cpn> </div> </body> <template id='cpn'> <div> <h2>{{cmovies}}</h2> <ul> <li v-for='cmovie in cmovies'>{{cmovie}}</li> </ul> <p>{{cmessage}}</p> </div> </template> <script> const cpn = { template:'#cpn', //props:['cmovies','cmessage'], props:{ //1 类型的限制(简单写法) //cmovies:Array,//要求数据必须是array类型 //cmessage:String //2 提供默认值(复杂写法) cmessage:{ type : String, default:'aaaaaaaaaa',//没有传值的情况下默认值 //required:true//传值的时候必须传入数值 }, cmovies:{ type:Array,//类型是对象或者数组时,默认值必须是一个函数 //default:[]//vue2.5以下 default(){//vue2.5以上 return [] } } }, data(){ return {} } } const app = new Vue({ el:"#app", data:{ message:'你好啊', movies:['海王','海贼王','海尔兄弟'] }, components:{ cpn //相当于cpn:cpn } }) </script>
props中的驼峰标识
<body> <div id="app"> 传递参数 <cpn v-bind:c-info="info" :child-my-message="myMessage"></cpn> <hr/> 不传入 显示默认值 <cpn> </cpn> </div> </body> <template id='cpn'> <!-- 如果不加根标签 会报错 [Vue warn]: Error compiling template: Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead. --> <div> <h2>{{cInfo}}</h2> <h2>{{childMyMessage}}</h2> </div> </template> <script> const cpn = { template:'#cpn', props:{ cInfo:{ type:Object, default(){ return {} } }, childMyMessage:{ default(){ return 'aaaaaaa' } } }, data(){ return {} } } const app = new Vue({ el:"#app", data:{ info:{ name:'aaa', age:16, height:1.88 }, myMessage:'bbbb' }, components:{ cpn //相当于cpn:cpn } }) </script>
注意点1 v-bind的时候 大写不支持 要改成-
注意点2 template下有多个{}时,要添加根标签 不然会报错
[Vue warn]: Error compiling template:
Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.
$emit从子组件-——》父组件的数据
子组件发射事件 通过$emit()来触发事件
methods:{ btnClick(category){ //console.log(category) //发射(事件名,传递的参数) this.$emit('categoryclick',category) } }
父组件接收事件 通过v-on来监听子组件事件
methods:{ cpnClick(category){ console.log('cpnClick',category) } }
<body> <div id="app"> <cpn @categoryclick='cpnClick'> </cpn> </div> </body> <!--子组件模板--> <template id='cpn'> <div> 子组件 <button v-for = "category in categories" @click='btnClick(category)'> {{category.name}} </button> </div> </template> <script> //子组件 const cpn = { template:'#cpn', data(){ return { categories:[ {id:'1',name:'热门推荐'}, {id:'2',name:'手机数码'}, {id:'3',name:'家用家电'}, {id:'4',name:'电脑办公'} ] } }, methods:{ btnClick(category){ //console.log(category) //发射(事件名,传递的参数) this.$emit('categoryclick',category) } } } //父组件 const app = new Vue({ el:"#app", components:{ cpn }, methods:{ cpnClick(category){ console.log('cpnClick',category) } } }) </script>