Vue.js 2.x笔记:组件(5)
1. 组件简介
组件(Component)是 Vue.js 最强大的功能之一,组件可以扩展 HTML 元素,封装可重用的代码。
组件:为了拆分Vue实例的代码量,以不同的组件来划分不同的功能模块,需要什么样的功能,可以去调用对应的组件。
模块化和组件化的区别:
◊ 模块化:是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一。
◊ 组件化:是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用。
2. 注册组件
2.1 全局组件
注册全局组件语法格式:
Vue.component(tagName, options)
其中,tagName 为组件名,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 局部组件
局部组件只能在当前Vue示例中使用。
<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
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 是单向传递,当父组件的属性变化时,将传递给子组件,但是不会反过来。这是为了防止子组件无意修改了父组件的状态。
3.1.3 props验证
为组件的 prop 指定验证要求,如果有一个需求没有被满足,则 Vue 会在控制台中警告。
Vue.component('my-component', { props: { // 基础的类型检查 (`null` 匹配任何类型) propA: Number, // 多个可能的类型 propB: [String, Number], // 必填的字符串 propC: { type: String, required: true }, // 带有默认值的数字 propD: { type: Number, default: 100 }, // 带有默认值的对象 propE: { type: Object, // 对象或数组且一定会从一个工厂函数返回默认值 default: function () { return { message: 'hello' } } }, // 自定义验证函数 propF: { validator: function (value) { // 这个值必须匹配下列字符串中的一个 return ['success', 'warning', 'danger'].indexOf(value) !== -1 } } } });
类型检查:type可以是下列原生构造函数中的一个:String、Number、Boolean、Array、Object、Date、Function、Symbol,也可以是一个自定义的构造函数,并且通过 instanceof 来进行检查确认。
示例:
<div id="app"> <parent-component></parent-component> </div> <template id="child-component1"> <h2>{{ message }}</h2> </template> <template id="child-component2"> <h2>{{ message }}</h2> </template> <template id="parent-component"> <div> <child-component1></child-component1> <child-component2></child-component2> </div> </template> <script> Vue.component('parent-component', { template: '#parent-component', components: { 'child-component1': { template: '#child-component1', data() { return { message: '子组件1' }; } }, 'child-component2': { template: '#child-component2', data() { return { message: '子组件2' }; } } } }); var vm = new Vue({ el: "#app" }); </script>
示例:
<div id="app"> <todo :todo-data="taskList"></todo> </div> <template id="tpl-todo-item"> <li>{{ id }} - {{ text }}</li> </template> <template id="tpl-todo-list"> <ul> <todo-item v-for="item in todoData" :id="item.id" :text="item.text"></todo-item> </ul> </template> <script> // 构建一个子组件 var todoItem = Vue.extend({ template: "#tpl-todo-item", props: { id: { type: Number, required: true }, text: { type: String, default: '' } } }) // 构建一个父组件 var todoList = Vue.extend({ template: "#tpl-todo-list", props: { todoData: { type: Array, default: [] } }, // 局部注册子组件 components: { todoItem: todoItem } }) // 注册到全局 Vue.component('todo', todoList) new Vue({ el: "#app", data: { taskList: [{ id: 1, text: 'New' }, { id: 2, text: 'InProcedure' }, { id: 3, text: 'Done' } ] } }); </script>
3.2 自定义事件:子组件向父组件传递数据
每一个Vue实例都实现事件接口:
$on(eventName):监听事件
$emit(eventName):触发事件
子组件需要向父组件传递数据时,子组件用
$emit(eventName)来触发事件,父组件用
$on(eventName)来监听子组件的事件。
<div id="app"> <searchbar></searchbar> </div> <template id="tpl-search-form"> <div class="input-group form-group" style="width: 500px;"> <input type="text" class="form-control" placeholder="请输入查询关键字" v-model="keyword" /> <span class="input-group-btn"> <input type="button" class="btn btn-primary" value="查询" @click="search"> </span> </div> </template> <template id="tpl-search-bar"> <searchform @onsearch="search"></searchform> </template> <script> // 构建一个子组件 var searchform = Vue.extend({ template: "#tpl-search-form", data: function () { return { keyword: 'libing' }; }, methods: { search: function () { this.$emit('onsearch', this.keyword); } } }); // 构建一个父组件 var searchbar = Vue.extend({ template: "#tpl-search-bar", components: { searchform: searchform }, methods: { search(keyword) { console.log(keyword); } } }) // 注册到全局 Vue.component('searchbar', searchbar); new Vue({ el: "#app" }); </script>
购物车示例:
<div id="app"> <shoppingcart :shopppingcarts="products" @calc="getTotal"></shoppingcart> <div>总计:{{ totalPrice }}</div> </div> <template id="shoppingcart"> <table> <tr> <th>商品ID</th> <th>商品名称</th> <th>单价</th> <th>数量</th> </tr> <tr v-for="item in shopppingcarts"> <td>{{ item.ID }}</td> <td>{{ item.ProductName }}</td> <td>{{ item.UnitPrice }}</td> <td><input type="text" v-model="item.Quantity" @change="calcTotal" /></td> </tr> </table> </template> <script> var shoppingcart = Vue.extend({ template: "#shoppingcart", props: ["shopppingcarts"], methods: { calcTotal: function () { this.$emit("calc"); } } }); new Vue({ el: "#app", components: { shoppingcart: shoppingcart }, data: { totalPrice: 100, products: [{ ID: 1, ProductName: "手机", UnitPrice: 1000, Quantity: 2 }, { ID: 2, ProductName: "电脑", UnitPrice: 5000, Quantity: 5 }] }, methods: { getTotal() { console.log(new Date()); this.totalPrice = 0; this.products.forEach(product => { this.totalPrice += product.UnitPrice * product.Quantity; }); } }, mounted() { //当vue执行完毕之后,去执行函数 this.getTotal(); } }); </script>
- vue非父子组件通讯笔记(引用本地文件vue.js及vuex.js)
- Vue.js 2.x笔记:安装与起步(1)
- Vue.js 2.x笔记:路由Vue Router(6)
- 【笔记】vue中引用了其他组件 (比如Bus.js),如何使this重新指向当前组件?
- Vue.js 2.x笔记:表单绑定(3)
- Vue.js学习笔记:组件
- vue.js实战笔记:父子组件之间的那些事儿
- Vue.js笔记-组件
- vueJS组件笔记(针对.vue组件)
- Vue.js 2.x笔记:服务请求axios(8)
- Vue.js学习笔记-1-组件
- Vue.js第四天学习笔记(组件)
- Vue.js 2.x笔记:基本语法(2)
- Vue.js 组件笔记
- vue.js学习笔记(三)--父子组件通信总结
- Vue.js 2.x笔记:状态管理Vuex(7)
- Vue.js 2.x笔记:指令(4)
- Vuejs刷新页面子组件数据丢失问题的一点笔记
- vuejs 组件的认识
- vue.js项目 el-input 组件 监听回车键实现搜索