vue基础篇---vue组件《2》
定义全局组件
我们通过Vue的component方法来定义一个全局组件。
<div id="app"> <!--使用定义好的全局组件--> <counter></counter> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script type="text/javascript"> // 定义全局组件,两个参数:1,组件名称。2,组件参数 Vue.component("counter",{ template:'<button v-on:click="count++">你点了我 {{ count }} 次,我记住了.</button>', data(){ return { count:0 } } }) var app = new Vue({ el:"#app" }) </script>
- 组件其实也是一个Vue实例,因此它在定义时也会接收:data、methods、生命周期函数等
- 不同的是组件不会与页面的元素绑定,否则就无法复用了,因此没有el属性。
- 但是组件渲染需要html模板,所以增加了template属性,值就是HTML模板
- 全局组件定义完毕,任何vue实例都可以直接在HTML中通过组件名称来使用组件了。
- data的定义方式比较特殊,必须是一个函数。
组件的复用
定义好的组件,可以任意复用多次:
<div id="app"> <!--使用定义好的全局组件--> <counter></counter> <counter></counter> <counter></counter> </div>
你会发现每个组件互不干扰,都有自己的count值。怎么实现的?
当我们定义这个 <counter>
组件时,它的data 并不是像这样直接提供一个对象:
data: { count: 0 }
取而代之的是,一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:
data: function () { return { count: 0 } }
如果 Vue 没有这条规则,点击一个按钮就会影响到其它所有实例!
局部注册
一旦全局注册,就意味着即便以后你不再使用这个组件,它依然会随着Vue的加载而加载。
因此,对于一些并不频繁使用的组件,我们会采用局部注册。
我们先在外部定义一个对象,结构与创建组件时传递的第二个参数一致:
const counter = { template:'<button v-on:click="count++">你点了我 {{ count }} 次,我记住了.</button>', data(){ return { count:0 } } };
然后在Vue中使用它:
var app = new Vue({ el:"#app", components:{ counter:counter // 将定义的对象注册为组件 } })
- components就是当前vue对象子组件集合。
- 其key就是子组件名称
- 其值就是组件对象的属性
- 效果与刚才的全局注册是类似的,不同的是,这个counter组件只能在当前的Vue实例中使用
组件通信
父向子传递props
比如我们有一个子组件:
Vue.component("introduce",{ // 直接使用props接收到的属性来渲染页面 template:'<h3>{{title}}</h3>', props:[title] // 通过props来接收一个父组件传递的属性 })
- 这个子组件中要使用title属性渲染页面,但是自己并没有title属性
- 通过props来接收父组件属性,名为title
父组件使用子组件,同时传递title属性:
<div id="app"> <h1>打个招呼:</h1> <!--使用子组件,同时传递title属性--> <introduce title="大家好,我是虎哥"/> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script type="text/javascript"> Vue.component("introduce",{ // 直接使用props接收到的属性来渲染页面 template:'<h1>{{title}}</h1>', props:['title'] // 通过props来接收一个父组件传递的属性 }) var app = new Vue({ el:"#app" }) </script>
传递复杂数据
我们定义一个子组件:
const myList = { template:'\ <ul>\ <li v-for="item in items" :key="item.id">{{item.id}} : {{item.name}}</li>\ </ul>\ ', props:{ // 通过props来接收父组件传递来的属性 items:{// 这里定义items属性 type:Array,// 要求必须是Array类型 default:[] // 如果父组件没有传,那么给定默认值是[] } } }
- 这个子组件可以对 items 进行迭代,并输出到页面。
- 但是组件中并未定义items属性。
- 通过props来定义需要从父组件中接收的属性
- items:是要接收的属性名称
- type:限定父组件传递来的必须是数组,否则报错
- default:默认值
我们在父组件中使用它:
<div id="app"> <h2>传智播客已开设如下课程:</h2> <!-- 使用子组件的同时,传递属性,这里使用了v-bind,指向了父组件自己的属性lessons --> <my-list :items="lessons"/> </div>
var app = new Vue({ el:"#app", components:{ myList // 当key和value一样时,可以只写一个 }, data:{ lessons:[ {id:1, name: 'java'}, {id:2, name: 'php'}, {id:3, name: 'ios'}, ] } })
子向父的通信
来看这样的一个案例:
<div id="app"> <h2>num: {{num}}</h2> <counter :count="num" @inc="increment" @dec="decrement"></counter> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script type="text/javascript"> Vue.component("counter", { template:'\ <div>\ <button @click="plus">加</button> \ <button @click="reduce">减</button> \ </div>', props:['count'], methods:{ plus(){ this.$emit("inc"); }, reduce(){ this.$emit("dec"); } } }) var app = new Vue({ el:"#app", data:{ num:0 }, methods:{ // 父组件中定义操作num的方法 increment(){ this.num++; }, decrement(){ this.num--; } } }) </script>
- vue提供了一个内置的this.$emit函数,用来调用父组件绑定的函数