组件(Component)是 Vue.js 最强大的功能之一,组件可以扩展 HTML 元素,封装可重用的代码。
组件:为了拆分Vue实例的代码量,以不同的组件来划分不同的功能模块,需要什么样的功能,可以去调用对应的组件。
模块化和组件化的区别:
◊ 模块化:是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一。
◊ 组件化:是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用。
2. 注册组件
Vue.js提供两种组件注册方式:全局注册和局部注册。
2.1 全局组件
全局注册需要在根实例初始化之前注册,这样组件才能在任意实例中被使用。
注册全局组件语法格式:
Vue.component(tagName, options)
其中,tagName 为组件名,options 为配置选项。
这条语句需要写在var vm = new Vue({ options })之前。
注册组件后调用方式:
<tagName></tagName>
所有实例都能用全局组件。
组件名定义方式:PascalCase和kebab-case。在组件命名时可以采用PascalCase或kebab-case,但在DOM中只能使用kebab-case。
PascalCase示例:
<div id="app"> <my-component></my-component> </div> <script> Vue.component('MyComponent', { template: '<div>标题</div>' }); var vm = new Vue({ el: "#app" }); </script>
kebab-case示例:
<div id="app"> <my-component></my-component> </div> <script> Vue.component('my-component', { template: '<div>标题</div>' }); var vm = new Vue({ el: "#app" }); </script>
<div id="app"> <home></home> </div> <script> Vue.component("home", { template: "<div>{{text}}</div>", data: function () { return { text: "主页" }; } }); new Vue({ el: "#app" }); </script>
<div id="app"> <home></home> </div> <script> var homeTpl = Vue.extend({ template: "<div>{{text}}</div>", data: function () { return { text: "主页" }; } }); Vue.component('home', homeTpl); new Vue({ el: "#app" }); </script>
使用template标签:
<div id="app"> <home></home> </div> <template id="tpl"> <div>{{text}}</div> </template> <script> Vue.component("home", { template: "#tpl", data: function () { return { text: "主页" }; } }); new Vue({ el: "#app" }); </script>
2.2 局部组件
局部组件只能在被注册的组件中使用,不能在其他组件中使用。
<div id="app"> <home></home> </div> <script> new Vue({ el: "#app", components: { "home": { template: "<div>{{text}}</div>", data: function () { return { text: "主页" }; } } } }); </script>
2.3 Vue.extend
2.3.1 基本使用
<div id="app"> <home></home> </div> <script> var home = Vue.extend({ template: "<div>标题</div>" }); Vue.component("home", home); new Vue({ el: "#app" }); </script>
2.3.2 参数data
data:在 Vue.extend() 中必须是函数。
<body> <task></task> <script> var task = Vue.extend({ template:"<div>{{ taskName }}</div>", data:function(){ return { taskName:"任务名称" } } }); new task().$mount("task"); </script> </body>
2.3.3 使用$mount
在实例中没有el选项时,可通过mount挂载。
mount:挂载,将vue实例挂靠在某个dom元素上的一个过程。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>libing.vue</title> <script src="node_modules/vue/dist/vue.min.js"></script> </head> <body> <div id="app"></div> <script> var home = Vue.extend({ template: "<div>标题</div>" }); new home().$mount("#app"); </script> </body> </html>
3. 组件通信
3.1 props:父组件向子组件传递数据
prop 是组件用来传递数据的自定义特性,在组件上注册自定义属性。
prop特性注册成为组件实例的属性。
props :父组件向子组件传递数据。
一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。
3.1.1 静态props
示例:
<div id="app"> <home text="主页"></home> </div> <script> var homeTpl = Vue.extend({ props:["text"], template: "<div>{{text}}</div>" }); Vue.component('home', homeTpl); new Vue({ el: "#app" }); </script>
3.1.2 动态props
使用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件。
<div id="app"> <home v-bind:text="text"></home> </div> <script> var homeTpl = Vue.extend({ props: ["text"], template: "<div>{{text}}</div>" }); Vue.component('home', homeTpl); new Vue({ el: "#app", data: { text: "主页" } }); </script>
由于HTML Attribute不区分大小写,当使用DOM模板时,camelCase的props名称要转为kebab-case。
<div id="app"> <home warning-text="提示信息"></home> </div> <script> Vue.component('home', { props: ['warningText'], template: '<div>{{ warningText }}</div>' }); var vm = new Vue({ el: "#app" }); </script>
传递的数据可以是来自父级的动态数据,使用指令v-bind来动态绑定props的值,当父组件的数据变化时,也会传递给子组件。
<div id="app"> <home v-bind:warning-text="warningText"></home> </div> <script> Vue.component('home', { props: ['warningText'], template: '<div>{{ warningText }}</div>' }); var vm = new Vue({ el: "#app", data: { warningText: '提示信息' } }); </script>
注:prop 是单向传递,当父组件的属性变化时,将传递给子组件,但是不会反过来。这是为了防止子组件无意修改了父组件的状态。
示例:
<template> <li>{{ id }}-{{ text }}</li> </template> <script> export default { name: "TodoItem", props: ["id", "text"] }; </script>