Vue组件开发实例(详细注释)
2018-03-27 20:28
651 查看
Vue组件开发实例:
css文件:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <link rel="stylesheet" href="SJStyle.css" /> <style> /* * 由于IE不支持<template>标签,所以template标签中的内容在IE下会直接显示出来。 * 将模板设为隐藏即可解决这个问题,template标签各浏览器支持请参考:http://caniuse.com/#feat=template */ #grid-template, #dialog-template { display: none; } </style> </head> <body> <div id="app"> <!-- 上部查询框:通过searchQuery过滤 --> <div class="container"> <div class="form-group"> <label>Search</label> <input type="text" class="search-input" v-model="searchQuery" /> </div> </div> <!-- 下部表格框 --> <div class="container"> <simple-grid :data-list="people" :columns="columns" :search-key="searchQuery"> </simple-grid> </div> </div> <!-- 父组件simple-grid --> <template id="grid-template"> <table> <!-- 表头,从columns里面取数据 --> <thead> <tr> <th v-for="col in columns"> {{ col.name | capitalize}} </th> <th>Delete</th> </tr> </thead> <!-- 表体,从people绑定的dataList里面取数据 --> <tbody> <!-- 这里有个filterBy过滤器的使用 --> <tr v-for="(index,entry) in dataList | filterBy searchKey"> <!-- 从columns里面取数据,判断是否有主键,有主键就显示编辑信息;没有就直接显示 --> <!-- 此处注意正好columns里的属性的值col.name,正好要是dataList里的entry的key,所以通过entry[col.name]去获取值 --> <td v-for="col in columns"> <span v-if="col.isKey"><a href="javascript:void(0)" @click="openEditItemDialog(entry[col.name])">{{entry[col.name]}}</a></span> <span v-else>{{entry[col.name]}}</span> </td> <!-- 删除的操作按钮,传了整条数据的信息作为参数 --> <td class="text-center"> <button class="btn-danger" @click="deleteItem(entry)">delete</button> </td> </tr> </tbody> </table> <!-- 新建操作按钮,传了标题作为参数 --> <div class="container"> <button class="btn" @click="openNewItemDialog('Create New Item')">Create</button> </div> <!-- 此处就是通过props指定父子组件通信的东西,就是让父组件的内容和子组件的内容对应 --> <modal-dialog :mode="mode" :title="title" :item="item" :fields="columns" v-on:create-item="createItem" v-on:update-item="updateItem"> </modal-dialog> </template> <!-- 子组件modal-dialog --> <template id="dialog-template"> <div class="dialogs"> <!-- v-bind:class通过show的值去判断是否新增class名,所以我们通过控制这个show值来达到显示和隐藏子组件的目的 --> <div class="dialog" v-bind:class="{ 'dialog-active': show }"> <div class="dialog-content"> <header class="dialog-header"> <h1 class="dialog-title">{{ title }}</h1> </header> <div class="dialog-body"> <!-- 通过遍历fields里的值,来加整个div --> <div v-for="field in fields" class="form-group"> <label>{{ field.name }}</label> <!-- 如果column有dataSource属性就显示下拉列表 --> <!-- 如果是编辑模式,并且有主键属性,就禁用 --> <select v-if="field.dataSource" v-model="item[field.name]" :disabled="mode === 2 && field.isKey"> <!-- 遍历column里的dataSource属性的值 --> <option v-for="opt in field.dataSource" :value="opt">{{ opt }}</option> </select> <!-- 如果没有dataSource属性,就显示文本框 --> <input v-else type="text" v-model="item[field.name]" :disabled="mode === 2 && field.isKey"> </div> </div> <footer class="dialog-footer"> <div class="form-group"> <label></label> <button class="btn-save" v-on:click="save">Save</button> <button class="btn-close" v-on:click="close">Close</button> </div> </footer> </div> </div> <div class="dialog-overlay"></div> </div> </template> <script src="vue.js"></script> <script> //注册父组件simple-grid Vue.component('simple-grid', { template: '#grid-template', //父组件其实也就是vue实例的子组件,所以也要通过props去与vue实例里的数据进行对应绑定:这里dataList绑定people,columns绑定columns,searchKey绑定searchQuery props: ['dataList', 'columns', 'searchKey'], //定义父组件里的数据 data: function() { return { mode: 0, title: '', keyColumn: '', item: {} } }, //通过钩子函数去设定name为主键,并赋值给keyColumn,就是this.keyColumn就是获取到主键"name" ready: function() { for(var i = 0; i < this.columns.length; i++) { if(this.columns[i].isKey) { this.keyColumn = this.columns[i]['name'] break; } } }, methods: { //点击新建按钮,弹出子组件 openNewItemDialog: function(title) { // 对话框的标题 this.title = title // mode = 1表示新建模式 this.mode = 1 // 初始化this.item this.item = {} // 广播事件,showDialog是modal-dialog组件的一个方法,传入参数true表示显示对话框 this.$broadcast('showDialog', true) }, //点击编辑弹出子组件 openEditItemDialog: function(key) { // 根据主键查找当前修改的数据 var currentItem = this.findItemByKey(key);//key就是传过来的name参数 // 修改对话框的标题 this.title = 'Edit Item - ' + key; // mode = 2表示修改模式 this.mode = 2; // 将选中的数据拷贝到this.item this.item = this.initItemForUpdate(currentItem); // 父组件让子组件显示:广播事件,传入参数true表示显示对话框 this.$broadcast('showDialog', true); }, // 就是一个深拷贝函数:弹出修改数据的对话框时,使用对象的深拷贝 initItemForUpdate(p, c) { c = c || {}; for(var i in p) { // 属性i是否为p对象的自有属性 if(p.hasOwnProperty(i)) { // 属性i是否为复杂类型 if(typeof p[i] === 'object') { // 如果p[i]是数组,则创建一个新数组 // 如果p[i]是普通对象,则创建一个新对象 c[i] = Array.isArray(p[i]) ? [] : {}; // 递归拷贝复杂类型的属性 this.initItemForUpdate(p[i], c[i]); } else { // 属性是基础类型时,直接拷贝 c[i] = p[i]; } } } return c; }, //该函数的作用就是通过传过来的name,查找返回那条数据 findItemByKey: function(key) { var keyColumn = this.keyColumn;//获取当前的主键 for(var i = 0; i < this.dataList.length; i++) { if(this.dataList[i][keyColumn] === key) {//this.dataList绑定的是vue实例的people对象 return this.dataList[i] } } }, //判断新增的item是否已经存在 itemExists: function() { var keyColumn = this.keyColumn;//获取主键列 for(var i = 0; i < this.dataList.length; i++) { //判断当前数据的主键列值是否已经在dataList里面存在 if(this.item[keyColumn] === this.dataList[i][keyColumn]){ return true; } } return false; }, //新建 createItem: function() { var keyColumn = this.keyColumn; if(!this.itemExists()) { // 将item追加到dataList this.dataList.push(this.item); // 广播事件,传入参数false表示隐藏对话框 this.$broadcast('showDialog', false) // 新建完数据后,重置item对象 this.item = {}; } else { alert(keyColumn + ' "' + this.item[keyColumn] + '" is already exists'); } }, //编辑 updateItem: function() { // 获取主键列 var keyColumn = this.keyColumn; for(var i = 0; i < this.dataList.length; i++) { // 根据主键查找要修改的数据,然后将this.item数据更新到this.dataList[i] if(this.dataList[i][keyColumn] === this.item[keyColumn]) { //如果主键的值相同,就把当前item里的值赋值给dataList for(var j in this.item) { this.dataList[i][j] = this.item[j]; } break; } } // 广播事件,传入参数false表示隐藏对话框 this.$broadcast('showDialog', false); // 修改完数据后,重置item对象 this.item = {}; }, //删除 deleteItem: function(entry) { var data = this.dataList;//获取当前dataList数据 data.forEach(function(item, i) { if(item === entry) { data.splice(i, 1); return; } }) } }, //局部注册子组件modal-dialog components: { 'modal-dialog': { template: '#dialog-template', data: function() { return { show: false // 对话框默认是不显示的 } }, /* 与父组件里面对应的数据: * mode = 1是新增数据模式,mode = 2是修改数据模式 * title表示对话框的标题内容 * fields表示对话框要显示的数据字段数组 * item是由simple-dialog传下来,用于绑定表单字段的 */ props: ['mode', 'title', 'fields', 'item'], methods: { //关闭 close: function() { this.show = false;//让子组件隐藏 }, //保存 save: function() { //如果是新增或编辑,就向父组件发派生事件 if(this.mode === 1) { // 使用$dispatch调用simple-grid的create-item事件 this.$dispatch('create-item'); } else if(this.mode === 2) { // 使用$dispatch调用simple-grid的update-item事件 this.$dispatch('update-item'); } } }, events: { 'showDialog': function(show) {//show接受父组件传来的参数,决定是显示还是隐藏对话框 this.show = show; } } } } }) var demo = new Vue({ el: '#app', data: { searchQuery: '', columns: [{ name: 'name', isKey: true }, { name: 'age' }, { name: 'sex', dataSource: ['Male', 'Female'] }], people: [{ name: 'Jack', age: 30, sex: 'Male' }, { name: 'Bill', age: 26, sex: 'Male' }, { name: 'Tracy', age: 22, sex: 'Female' }, { name: 'Chris', age: 36, sex: 'Male' }] } }) </script> </body> </html>
css文件:
* { margin: 0; padding: 0; box-sizing: border-box; font-family: Helvetica, simhei, Arial, sans-serif; } html { font-size: 1rem; } body{ margin-top: 100px; } table, td, th { border-collapse: collapse; border-spacing: 0 } table { width: 100%; } td, th { border: 1px solid #bcbcbc; padding: 5px 10px; } th { padding: 10px; font-weight: 400; color: #fff; background: #0090d3; cursor: pointer; } tr:nth-of-type(odd) { background: #fff } tr:nth-of-type(even) { background: #eee } h1{ font-size: 1.5rem; margin-bottom: 2rem; } input { outline: none } input[type=text] { padding: 3px 6px; font-size: 1.2rem; border: 1px solid #ccc; } input[type=text]:focus { border-color: #0090d3; transition: .3s ease-in; } button { display: inline-block; box-sizing: border-box; padding: 10px 30px; background: #0090d3; color: #fff; border: 1px solid #0090d3; border-radius: 3px; outline: 0; transition: .4s ease-out; } button:hover, button:focus { opacity: 0.8; cursor: pointer; transition: .15s ease-in; } #app { margin: 0 auto; max-width: 640px; } .btn-danger{ padding: 5px 15px; border: 1px solid salmon; background: salmon; } .btn-save{ border: 1px solid #0090d3; background: #0090d3; } .btn-close{ border: 1px solid #ccc; background: #ccc; } .container { padding-left: 15px; padding-right: 15px; margin: 10px; } .search-input { width: 80%; } .form-group { margin: 10px; } .form-group > label { display: inline-block; padding-right: 1rem; width: 5rem; text-align: right; } .form-group > input, .form-group > select { display: inline-block; height: 1.8rem; line-height: 1.8rem; } .text-center { text-align: center; } .dialog { width: 480px; position: fixed; left: 50%; top: 2em; transform: translateX(-50%); z-index: 2000; visibility: hidden; backface-visibility: hidden; perspective: 1300px; } .dialog-active { visibility: visible; } .dialog-active .dialog-content { opacity: 1; transform: rotateY(0); } .dialog-active ~ .dialog-overlay { opacity: 1; visibility: visible; } .dialog-content { border-radius: 3px; background: #fff; overflow: hidden; box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); transition: .5s ease-in-out; opacity: 0; transform-style: preserve-3d; transform: rotateY(-70deg); } .dialog-header { background: #0090d3; color: #fff; } .dialog-title { margin: 0; font-size: 2em; text-align: center; font-weight: 200; line-height: 2em; } .dialog-body { padding: 2em; } .dialog-footer { margin: 0 2em; padding: 1em 0; border-top: 1px solid rgba(0, 0, 0, 0.1); } .dialog-overlay { content: ""; position: fixed; visibility: hidden; top: 0; left: 0; right: 0; bottom: 0; z-index: 1000; opacity: 0; background: rgba(0, 0, 0, 0.5); transition: all .6s; }
相关文章推荐
- Vue组件大全包括(UI组件,开发框架,服务端,辅助工具,应用实例,Demo示例)
- vue-star评星组件开发实例
- vue.js指令和组件详细介绍及实例
- 用webpack2.0构建vue2.0单文件组件超级详细精简实例
- 打通前后端全栈开发node+vue进阶【课程学习系统项目实战详细讲解】(3):用户添加/修改/删除 vue表格组件 vue分页组件
- Vue.js组件使用开发实例教程
- Vue.js 父子组件通讯开发实例
- WordPress 插件开发实例 – 详细注释的 Widget 开发例子
- vue.js实例对象+组件树的详细介绍
- vue.js表格组件开发的实例详解
- WordPress 插件开发实例 – 详细注释的 Widget 开发例子
- Vue.js 父子组件通讯开发实例
- Vue拖拽组件开发实例详解
- vue.js开发实现全局调用的MessageBox组件实例代码
- vuejs组件开发之手风琴菜单组件实例
- Vue.js手风琴菜单组件开发实例
- 利用vue开发一个所谓的数独方法实例
- vue组件的开发使用-组件的创建
- Vue中封装input组件的实例详解
- COM/DCOM开发练习之进程外组件实例