组件(Component)是 Vue.js最强大的功能之一。组件能够扩展 HTML元素,封装可重用的代码组件是自定义元素(对象)。vue
官方推荐组件标签名是使用-
链接的组合词,例如:<my-hello></my-hello>
。缓存
使用这种方式建立组件首先须要使用Vue.extend()
建立一个组件构造器,而后使用Vue.component(标签名,组件构造器)
,根据组件构造器来建立组件。app
//1.建立构造器 var MyComponent=Vue.extend({ template:'<h3>Hello World</h3>' }); //2.建立组件 Vue.component('my-hello',MyComponent); //3.使用组件 <div id="app"> <my-hello></my-hello> </div>
这种建立组件的方式比较麻烦,使用的较少。dom
使用Vue.component(标签名,组件模板)
,根据组件构造器来建立组件。函数
//1.建立组件 Vue.component('my-world', { template: '<h2>hello vue.js</h2>' }); //2.使用组件 <div id="app"> <my-world></my-world> </div>
组件分为全局组件和局部组件。this
使用Vue.component()
建立的组件都是全局组件。这样的组件在任何组件内都能使用。上面咱们建立就是全局组件。code
局部组件通常都是定义在实例的选项中,称为实例的子组件。相应的,实例也被称为父组件。component
//1.定义组件 new Vue({ el: '#app', components: { dawei: { template: '<h2>my name is dawei</h2>' } } }); //2.使用组件 <div id="app"> <dawei></dawei> </div>
不少时候咱们的template
模板中须要存放不少标签内容,这样的话写起来会很麻烦。这时候咱们可使用template
标签。对象
用法以下:事件
<template id="wbs"> //使用template标签 <div> <h2>hello {{msg}}</h2> <ul> <li v-for="value in arr"> {{value}} </li> </ul> </div> </template> new Vue({ el: '#app', components: { 'my-dawei': { template: '#wbs', //选择template标签 data() { return { msg: 'vue.js', arr: ["a", "b", "c", "d"] } } } } });
这里涉及到的几个知识点得着重提一下:
template
模板中,全部的元素必须放置在一个根元素中,要否则会报错。例子中咱们将元素放置在了<div>
标签中。data
选项必须是一个函数类型,使用return
返回全部的数据。不少时候项目中须要在某一个地方动态的使用不一样的组件,这时候就须要使用动态组件。
动态组件的使用须要绑定is
属性:
<component :is="flag"></component>
简单示例:
//点击按钮显示不一样的组件 <div id="app"> <button type="button" @click="flag='my-a'">显示a组件</button> <button type="button" @click="flag='my-b'">显示b组件</button> <component :is="flag"></component> //传入flag </div> new Vue({ el: '#app', data: { flag: 'my-a' //给flag赋值 }, components: { 'my-a': { template: '<p>我是a组件</p>', }, 'my-b': { template: '<p>我是b组件</p>' } } });
使用keep-alive
组件缓存非活动组件,能够保留状态,避免从新渲染,默认每次都会销毁非活动组件并从新建立。
使用范例:
<keep-alive> <component :is="flag"></component> </keep-alive> <div id="app"> <button type="button" @click="flag='my-x'">x</button> <button type="button" @click="flag='my-y'">y</button> <keep-alive> <component :is="flag"></component> </keep-alive> </div> new Vue({ el: '#app', data: { flag: 'my-x' }, components: { 'my-x': { template: '<p>{{x}}</p>', data() { return { x: Math.random() } } }, 'my-y': { template: '<p>{{y}}</p>', data() { return { y: Math.random() } } } } });
这样的话,第一次产生的随机数就会被缓存,再次切换的时候也不会发生改变。
在一个组件内部定义另外一个组件,那么这对组件称为父子组件。子组件只能在父组件内部使用。默认状况下,每一个组件实例的做用域是独立的,子组件没法访问父组件中的数据,一样,父组件也没法访问子组件中的数据。
<div id="app"> <my-a></my-a> <!-- 父组件 --> </div> <template id="a"> <div> <p>{{msg}}</p> <my-b></my-b> <!-- 在父组件中调用子组件 --> </div> </template> <template id="b"> <div> <p>{{mydata}}</p> </div> </template> <script> new Vue({ //根组件 el: '#app', components: { //子组件写在components选项中 "my-a": { //b组件的父组件 template: "#a", data() { return { msg: '我是父组件', } }, components: { //子组件写在父组件的components选项中 "my-b": { template: "#b", data() { return { mydata: "我是子组件" } } } } } } }); </script>
步骤:
改进上面的例子:
<div id="app"> <my-a></my-a> </div> <template id="a"> <div> <p>{{msg}}</p> <p>这是要传递给子组件的值:{{myname}}</p> <my-b :name="myname"></my-b> <!-- 绑定子组件想要获取的数据 --> </div> </template> <template id="b"> <div> <p>{{mydata}}</p> <p>这是父组件传递过来的数据:{{name}}</p> </div> </template> <script> new Vue({ el: '#app', data: {}, components: { "my-a": { template: "#a", data() { return { msg: '我是a组件', myname: '子组件b你好,我是父组件a' } }, components: { "my-b": { template: "#b", data() { return { mydata: "我是b组件" } }, props: ["name"] //子组件使用props声明想要获取的数据 } } } } }); </script>
步骤:
//子组件‘my-b’内部 methods:{ send(){//使用$emit()触发一个事件,发送数据,this指当前子组件实例 this.$emit('e-world', this.senddata); } } //在调用子组件的地方监听子组件触发的事件,调用本身的方法获取数据 <my-b @e-world="getData"></my-b> methods: { getData(data) { //参数是子组件传递过来的数据 this.revicedata = data; } }
props是单向数据绑定的,当父组件数据发生变化时,将传递给子组件,可是不会反过来。并且不容许子组件直接修改父组件中的数据,强制修改会报错。
解决方案:
//使用.sync <my-b :name.sync="myname"></my-b> //子组件修改父组件传入的值name,触发update更新事件 this.$emit('update:name', "vuejs");
data() { return { //将要传递的数据放入message对象中 message: { hello: '子组件b你好,我是父组件a' } } } <my-b :message="message"></my-b> //传递这个对象给子组件 methods: { //在子组件内部修改这个值,这样就会同步传递给父组件。 edit() { this.message.hello = "hahahahh"; } }
非父子组件间的通讯,能够经过一个空的Vue实例做为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现非父子组件间的通讯。
var Event = new Vue(); //空vue实例 methods: { send() { //触发emit事件 Event.$emit("hello", this.asmsg); } } mounted() { //在子组件的钩子函数中监听该事件 Event.$on('hello', data => { //获取值 this.bsmsg = data; }) }
用来获取组件中的原内容
var vm = new Vue({ el: '#app', components: { 'my-hello': { template: '#hello' } } }); <div id="app"> <my-hello>hello vue.js</my-hello> </div> <template id="hello"> <div> <slot>若是没有原内容,则显示该内容</slot> </div> </template>
若是组件标签中没有内容就会显示slot中的内容,这也就是所谓的单个插槽。
还能够对显示的内容进行分组,这就是具名插槽,能够操做标签组中的内容:
<div id="app"> <my-hello> <ul slot="s1"> <li>aaa</li> <li>bbb</li> <li>ccc</li> </ul> <ol slot="s2"> <li>111</li> <li>222</li> <li>333</li> </ol> </my-hello> </div> <template id="hello"> <div> <slot name="s2"></slot> //为插槽指定名称 将名为s2的内容放置在这里 <p>hello vue.js</p> <slot name="s1"></slot> //将名为s1的内容放置在这里 </div> </template>
这样,就能够对组件中的内容实时操做。