zoukankan      html  css  js  c++  java
  • Vue组件开发实例(详细注释)

      Vue组件开发实例:

    <!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 {
         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- 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 {
         80%;
    }
    
    .form-group {
        margin: 10px;
    }
    
    .form-group > label {
        display: inline-block;
        padding-right: 1rem;
         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 {
         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;
    }
  • 相关阅读:
    CollectionView Header And Footer 的使用
    UICollectionView 的添加自定义高度的区头
    利用SDWebImage 清理缓存
    iOS tableView 中 UITableView中UITableViewStyleGrouped和UITableViewStylePlain的区别
    关于tableview的分割线隐藏问题
    改变输入框的placehould的颜色 和边框颜色
    将代码在有xib得情况下设置到最底层(即执行顺序不是先执行xib) 将图片毛玻璃状态
    通知监听键盘高度变化 自适应键盘高度
    iOS 定义枚举
    iOS 快速存储到本地
  • 原文地址:https://www.cnblogs.com/goloving/p/8659956.html
Copyright © 2011-2022 走看看