vue.js之组件
代码复用一直是软件开发中长期存在的问题,每个开发者都想要再次使用之前写好的代码,又担心引入这段代码后对现有的程序产生影响。现在web Components的出现提供了一种新的思路,可以自定义tag标签,并拥有自身的模板,样式和交互。Vue.js提供了自己的组件系统,支持自定义tag元素和原生HTML元素的扩展
一、基本步骤
1、vue的组件使用有三个步骤:创建组件构造器、注册组件和使用组件
- 调用Vue.extend({...})创建组件构造器
- 用Vue.component()方法注册组件
- 在Vue实例的作用范围内使用组件
下面的代码演示了这三个步骤
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue组件</title> <script src="bower_components/vue/dist/vue.js"></script> </head> <body> <div id="box"> <!--#box是vue实例挂载的元素,应该在挂载元素范围内使用组件--> <aaa></aaa> </div> <script> <!--定义一个组件--> // 全局组件 //1.创建一个组件构造器 var Aaa=Vue.extend({ template:'<h3> 我是标题3</h3>' }); //2.注册组件,并指定组件的标签,组件的HTML标签为<aaa> Vue.component('aaa',Aaa); var vm=new Vue({ el:"#box" }) </script> </body> </html>
运行结果:
2、理解组件的创建和注册
-
Vue.extend()
是Vue构造器的扩展,调用Vue.extend()
创建的是一个组件构造器。
-
Vue.extend()
构造器有一个选项对象,选项对象的template
属性用于定义组件要渲染的HTML。
- 使用
Vue.component()
注册组件时,需要提供2个参数,第1个参数时组件的标签,第2个参数是组件构造器。 - 组件应该挂载到某个Vue实例下,否则它不会生效。
<!DOCTYPE html> <html> <body> <div id="app1"> <my-component></my-component> </div> <div id="app2"> <my-component></my-component> </div> <!--该组件不会被渲染--> <my-component></my-component> </body> <script src="js/vue.js"></script> <script> var myComponent = Vue.extend({ template: '<div>This is a component!</div>' }); Vue.component('my-component', myComponent); var app1 = new Vue({ el: '#app1' }); var app2 = new Vue({ el: '#app2' }) </script> </html>
注意:虽然上面有三个地方使用了<my-component>标签,但是只有#app1和#app2下的<my-component>标签才起到作用。因为第三个没有被挂载
二、全局注册与局部注册
1、全局注册
全局注册需要确保在根实例初始化之前注册,这样才能使组件在任意实例中被使用,注册方式如下:
<!DOCTYPE html> <html> <body> <div id="app1"> <my-component></my-component> </div> </body> <script src="js/vue.js"></script> <script> var myComponent = Vue.extend({ template: '<div>This is a component!</div>' }) Vue.component('my-component', myComponent) //这条语句应该写在var app1=new Vue({....})之前,注册成功之后,就可以在模块中以自定义元素<my-cpmponent>的形式使用组件 var app1 = new Vue({ el: '#app1' });</script> </html>
运行结果:
This is a component!
2、局部注册
组件内使用其他组件,可以用选项对象的components属性实现局部注册。
<!DOCTYPE html> <html> <body> <div id="app"> <!-- 3. my-component只能在#app下使用--> <my-component></my-component> </div> </body> <script src="js/vue.js"></script> <script> // 1.创建一个组件构造器 var myComponent = Vue.extend({ template: '<div>This is my first component!</div>' }) new Vue({ el: '#app', components: { // 2. 将myComponent组件注册到Vue实例下 'my-component' : myComponent } }); </script> </html>
三、父组件与子组件
在 组件中定义并使用其他组件,这就构成了父子组件的关系
<!DOCTYPE html> <html> <body> <div id="app"> <parent-component> </parent-component> </div> </body> <script src="js/vue.js"></script> <script> var Child = Vue.extend({ template: '<p>This is a child component!</p>' }) var Parent = Vue.extend({ // 在Parent组件内使用<child-component>标签 template :'<p>This is a Parent component</p><child-component></child-component>', components: { // 局部注册Child组件,该组件只能在Parent组件内使用 'child-component': Child } }) // 全局注册Parent组件 Vue.component('parent-component', Parent) new Vue({ el: '#app' }) </script> </html>
运行结果:
理解上面的代码:
var Child = Vue.extend(...)
定义一了个Child组件构造器var Parent = Vue.extend(...)
定义一个Parent组件构造器components: { 'child-component': Child }
,将Child组件注册到Parent组件,并将Child组件的标签设置为child-component
。template :'<p>This is a Parent component</p><child-component></child-component>'
,在Parent组件内以标签的形式使用Child组件。Vue.component('parent-component', Parent)
全局注册Parent组件- 在页面中使用<parent-component>标签渲染Parent组件的内容,同时Child组件的内容也被渲染出来
四、组件注册语法糖
前面组件注册的方式有点繁琐,Vue.js为了简化这个过程,提供了注册语法糖
1、使用vue.componet()直接创建和注册组件
// 全局注册,my-component1是标签名称 Vue.component('my-component1',{ template: '<div>This is the first component!</div>' }) var vm1 = new Vue({ el: '#app1' })
Vue.component()
的第1个参数是标签名称,第2个参数是一个选项对象,使用选项对象的template属性定义组件模板。
使用这种方式,Vue在背后会自动地调用Vue.extend()
。
2、在选项对象的components属性中实现局部注册:
var vm2 = new Vue({ el: '#app2', components: { // 局部注册,my-component2是标签名称 'my-component2': { template: '<div>This is the second component!</div>' }, // 局部注册,my-component3是标签名称 'my-component3': { template: '<div>This is the third component!</div>' } } })
五、使用template和javascript标签
尽管语法糖简化了组件注册,但在template选项中拼接HTML元素比较麻烦,这也导致了HTML和JavaScript的高耦合性。
庆幸的是,Vue.js提供了两种方式将定义在JavaScript中的HTML模板分离出来。
1、使用javascript
<!DOCTYPE html> <html> <body> <div id="app"> <my-component></my-component> </div> <!--type指定为text/x-template,意在告诉浏览器这不是一段js脚本,浏览器在解析HTML文档时会忽略<script>标签内定义的内容--> <script type="text/x-template" id="myComponent"> <div>This is a component!</div> </script> </body> <script src="js/vue.js"></script> <script> Vue.component('my-component',{ template: '#myComponent' //与上面的模版id相对应
}) new Vue({ el: '#app' }) </script> </html>
template选项现在不再是HTML元素,而是一个id,Vue.js根据这个id查找对应的元素,然后将这个元素内的HTML作为模板进行编译
运行结果:
2、使用template标签
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"> <my-component></my-component> </div> <!--使用template标签不需要使用type属性--> <template id="myComponent"> <div>This is a component!</div> </template> </body> <script src="js/vue.js"></script> <script> Vue.component('my-component',{ template: '#myComponent' }) new Vue({ el: '#app' }) </script> </html>
在理解了组件的创建和注册过程后,我建议使用<script>或<template>标签来定义组件的HTML模板。
这使得HTML代码和JavaScript代码是分离的,便于阅读和维护。
六、使用个props
组件实例的作用域是孤立的。这意味着不能并且不应该在子组件的模板内直接引用父组件的数据。可以使用 props 把数据传给子组件。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="bower_components/vue/dist/vue.js"></script> <style> </style> </head> <body> <div id="box"> <div>{{a}}</div> <aaa> {{msg}} </aaa> </div> <template id="aa"> <h1>11111</h1>
<!--将父组件数据通过已定义好的props属性传递给子组件--> <bbb :mmm="msg2" :my-msg="msg"></bbb> </template> <script> var vm=new Vue({ el:'#box', data:{ a:'a' }, components:{ 'aaa':{ data(){ return { msg:111, msg2:'我是父组件的数据' } }, template:'#aa', components:{ 'bbb':{ props:{ 'mmm':String, 'myMsg':Number }, template:'<h3>我是bbb组件->{{mmm}} <br> {{myMsg}}</h3>' } } } } }); </script> </body> </html>
运行结果:
注意:在子组件中定义prop时,使用了camelCase命名法。由于HTML特性不区分大小写,camelCase的prop用于特性时,需要转为 kebab-case(短横线隔开)。例如,在prop中定义的myName,在用作特性时需要转换为my-name。