• Vue.js使用-组件示例(实现数据的CRUD)


    1.业务场景
    用户(姓名,年龄,性别)的增删改查

    2.数据格式
    定义字段,name:字段名称,iskey:是否主键(添加,修改数据标志),dataSource:可选列表(下拉框选项)

    columns: [{name: 'name', iskey: true}, {name: 'age'},{name: 'sex', dataSource:['Male', 'Female']}],
    

    定义数据,用户信息列表

    peoples: [{name: 'shijingjing', age: 30, sex:'Male'},{name: 'renjiangfeng', age:29, sex:'Female'}]
    

    3.组件定义
    我们需要定义两个组件,表格显示组件,信息维护组件。

    4.表格显示组件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="styles/index.css">
    </head>
    <body>
        <div id="app">
            <div class="container">
                <simple-grid v-bind:columns="columns" v-bind:peoples="peoples"></simple-grid>
            </div>
        </div>
        <template id="grid-template">
            <table>
                <tr>
                    <th v-for="column in columns">{{ column.name | capitalize }}</th>
                    <th>Delete</th>
                </tr>
                <tr v-for="people in peoples">
                    <td v-for="column in columns">
                        <span>{{ people[column.name] }}</span>
                    </td>
                    <td style="text-align: center"><button class="btn-delete" v-on:click="deleteItem(people)">delete</button></td>
                </tr>
            </table>
        </template>
    
    </body>
    <script src="js/vue.js"></script>
    <script>
        Vue.component(
            'simple-grid',{
                template: '#grid-template',
                props: ['peoples', 'columns'],
                methods: {
                    deleteItem: function (people) {
                        for(var i=0;i<this.peoples.length;i++){
                            if(this.peoples[i] == people){
                                this.peoples.splice(i, 1);
                                return
                            }
                        }
                    }
                }
            }
        )
    
        new Vue({
            el: '#app',
            data: {
                columns: [{name: 'name', iskey: true}, {name: 'age'},{name: 'sex', dataSource:['Male', 'Female']}],
                peoples: [{name: 'shijingjing', age: 30, sex:'Male'},{name: 'renjiangfeng', age:29, sex:'Female'}]
            }
        })
    </script>
    </html>
    

    运行结果:

    定义了一个simple-grid组件,将Vue对象中的columns,peoples属性值绑定到组件,表头使用columns属性值,数据列使用peoples属性值。
    deleteItem方法,用来删除peoples对应的元素。

    5.信息维护组件
    表格组件实现了数据的查询和删除,添加和修改要通过信息维护组件来实现。
    把信息维护组件作为表格组件的子组件,来实现表格和弹窗数据的交互,事件的传递。
    1)新增

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="styles/index.css">
    </head>
    <body>
        <div id="app">
            <div class="container">
                <simple-grid v-bind:columns="columns" v-bind:peoples="peoples"></simple-grid>
            </div>
        </div>
        <template id="grid-template">
            <table>
                <tr>
                    <th v-for="column in columns">{{ column.name | capitalize }}</th>
                    <th>Delete</th>
                </tr>
                <tr v-for="people in peoples">
                    <td v-for="column in columns">
                        <span>{{ people[column.name] }}</span>
                    </td>
                    <td style="text-align: center"><button class="btn-delete" v-on:click="deleteItem(people)">delete</button></td>
                </tr>
            </table>
            <div class="container">
                <button v-on:click="openItemDialog('创建')">创建</button>
            </div>
            <modal-dialog v-bind:mode="mode" v-bind:title="title" v-bind:item="item" v-bind:fields="columns" v-on:create_item="createItem"></modal-dialog>
        </template>
    
        <template id="dialog-template">
            <div class="dialog" v-bind:class="{'dialog-active':show}">
                    <div class="dialog-header">{{ title }}</div>
                    <div class="dialog-body">
                        <div v-for="field in fields" class="form-group">
                            <label>{{ field.name }}</label>
                            <input type="text" v-model="item[field.name]">
                        </div>
                    </div>
                    <div class="dialog-footer">
                        <div class="form-group">
                            <label></label>
                            <button class="btn-save" v-on:click="save">保存</button>
                            <button class="btn-close" v-on:click="close">关闭</button>
                        </div>
                    </div>
            </div>
            <div class="dialog-overlay"></div>
        </template>
    </body>
    <script src="js/vue.js"></script>
    <script>
        Vue.component(
            'simple-grid',{
                template: '#grid-template',
                data: function () {
                    return{
                        mode: 0,
                        title: '',
                        item: {},
                    }
                },
                props: ['peoples', 'columns', 'search'],
                methods: {
                    openItemDialog:function (title) {
                        this.title = title;
                        this.mode = 1;
                        this.item = {};
                        this.$broadcast('showDialog', true);
                    },
                    deleteItem: function (people) {
                        for(var i=0;i<this.peoples.length;i++){
                            if(this.peoples[i] == people){
                                this.peoples.splice(i, 1);
                                return
                            }
                        }
                    },
                    createItem: function () {
                        this.peoples.push(this.item);
                        this.$broadcast("showDialog", false);
                        this.item = {};
                    }
                },
                components:{
                    'modal-dialog':{
                        template: '#dialog-template',
                        data: function () {
                            return {
                                show: false
                            }
                        },
                        props: ['mode', 'fields', 'item', 'title'],
                        methods:{
                            close:function () {
                                this.show = false;
                            },
                            save:function () {
                                if(this.mode ==1){
                                    this.$dispatch('create_item');
                                }
                            }
                        },
                        events:{
                            'showDialog': function (show) {
                                this.show = show
                            }
                        }
    
                    }
                }
            }
        )
    
        new Vue({
            el: '#app',
            data: {
                columns: [{name: 'name'}, {name: 'age'}],
                peoples: [{name: 'shijingjing', age: 30},{name: 'renjiangfeng', age:29}]
            }
        })
    </script>
    </html>
    

    运行结果:

    弹窗组件modal-dialog定义了一个show属性,v-bind:class="{'dialog-active':show},show为false时隐藏,true显示弹窗。
    子组件使用了父组件的mode,fields,item,title四个属性。
    mode:1-新增,2-修改
    fields:父组件的columns属性,用来显示需要维护的字段
    item:新添加的数据对象
    title:弹窗title(新增or修改)
    点击父组件创建按钮openItemDialog时,会将showDialog事件broadcast到子组件。

    events:{
        'showDialog': function (show) {
            this.show = show
        }
    }
    

    showDialog完成弹窗的显示隐藏
    modal-dialog组件的template,#dialog-template绑定了新数据对象item,维护完毕,点击保存按钮时,触发save方法,将保存事件派发到父组件处理。

    save:function () {
        if(this.mode ==1){
            this.$dispatch('create_item');
        }
    }
    

    create_item绑定了父组件的createItem方法

    v-on:create_item="createItem"
    

    createItem中将新的数据对象添加到数据列表,广播showDialog事件到子组件,关闭弹窗,添加数据完毕。

    createItem: function () {
        this.peoples.push(this.item);
        this.$broadcast("showDialog", false);
        this.item = {};
    }
    

    2)修改

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="styles/index.css">
    </head>
    <body>
        <div id="app">
            <div class="container">
                <simple-grid v-bind:columns="columns" v-bind:peoples="peoples"></simple-grid>
            </div>
        </div>
        <template id="grid-template">
            <table>
                <tr>
                    <th v-for="column in columns">{{ column.name | capitalize }}</th>
                    <th>Delete</th>
                </tr>
                <tr v-for="people in peoples | filterBy search">
                    <td v-for="column in columns">
                        <span v-if="column.iskey">
                            <a href="javascript:void(0)" v-on:click="editItemDialog(people[column.name])">{{ people[column.name] }}</a>
                        </span>
                        <span v-else>{{ people[column.name] }}</span>
                    </td>
                    <td style="text-align: center"><button class="btn-delete" v-on:click="deleteItem(people)">delete</button></td>
                </tr>
            </table>
            <modal-dialog v-bind:mode="mode" v-bind:title="title" v-bind:item="item" v-bind:fields="columns" v-on:create_item="createItem" v-on:update_item="updateItem"></modal-dialog>
        </template>
    
        <template id="dialog-template">
            <div class="dialog" v-bind:class="{'dialog-active':show}">
                    <div class="dialog-header">{{ title }}</div>
                    <div class="dialog-body">
                        <div v-for="field in fields" class="form-group">
                            <label>{{ field.name }}</label>
                            <input type="text" v-model="item[field.name]" v-bind:disabled="mode ==2 && field.iskey">
                        </div>
                    </div>
                    <div class="dialog-footer">
                        <div class="form-group">
                            <label></label>
                            <button class="btn-save" v-on:click="save">保存</button>
                            <button class="btn-close" v-on:click="close">关闭</button>
                        </div>
                    </div>
            </div>
            <div class="dialog-overlay"></div>
        </template>
    </body>
    <script src="js/vue.js"></script>
    <script>
        Vue.component(
            'simple-grid',{
                template: '#grid-template',
                data: function () {
                    return{
                        mode: 0,
                        title: '',
                        item: {},
                        keyColumn: ''
                    }
                },
                ready: function () {
                    for(var i=0;i<this.columns.length;i++){
                        if(this.columns[i].iskey){
                            this.keyColumn = this.columns[i].name;
                            break;
                        }
                    }
                },
                props: ['peoples', 'columns', 'search'],
                methods: {
                    editItemDialog: function (key) {
                        this.title ='修改-' + key;
                        this.mode = 2;
                        var currItem = this.findItemByKey(key);
                        console.log(currItem)
                        this.item = currItem;
                        this.$broadcast('showDialog', true);
                    },
                    deleteItem: function (people) {
                        for(var i=0;i<this.peoples.length;i++){
                            if(this.peoples[i] == people){
                                this.peoples.splice(i, 1);
                                return
                            }
                        }
                    },
                    updateItem: function () {
                      for(var i=0;i<this.peoples.length;i++){
                          if(this.peoples[i][this.keyColumn] == this.item[this.keyColumn]){
                              for(var key in this.item){
                                  this.peoples[i][key] = this.item[key];
                              }
                              break;
                          }
                      }
                      this.$broadcast('showDialog', false);
                      this.item = {};
                    },
                    findItemByKey: function (key) {
                        for(var i=0; i<this.peoples.length;i++){
                            if(this.peoples[i].name == key){
                                return this.peoples[i];
                            }
                        }
                    }
                },
                components:{
                    'modal-dialog':{
                        template: '#dialog-template',
                        data: function () {
                            return {
                                show: false
                            }
                        },
                        props: ['mode', 'fields', 'item', 'title'],
                        methods:{
                            close:function () {
                                this.show = false;
                            },
                            save:function () {
                                if(this.mode ==1){
                                    this.$dispatch('create_item');
                                }
                                else if(this.mode == 2){
                                    this.$dispatch('update_item');
                                }
                            }
                        },
                        events:{
                            'showDialog': function (show) {
                                this.show = show
                            }
                        }
    
                    }
                }
            }
        )
    
        new Vue({
            el: '#app',
            data: {
                columns: [{name: 'name', iskey: true}, {name: 'age'}],
                peoples: [{name: 'shijingjing', age: 30},{name: 'renjiangfeng', age:29}]
            }
        })
    </script>
    </html>
    

    运行结果:

    数据使用iskey标志主键,更新时,editItemDialog中使用findItemByKey根据主键找到要修改的数据,赋给item属性(供子组件使用),
    然后broadcast广播showDialog事件,子组件接收到showDialog通知后,显示弹窗。
    点击保存按钮时,调用save方法,将update_item事件派发到父组件

    save:function () {
        if(this.mode ==1){
            this.$dispatch('create_item');
        }
        else if(this.mode == 2){
            this.$dispatch('update_item');
        }
    }
    

    父组件中将item更新到数据列表peoples,需要注意的是,在findItemByKey方法时,需要使用深度拷贝,将数据对象赋给item,而不是直接将数据对象的引用赋给item,
    这样当子组件中model属性值更新时,无论是否点击保存按钮,表格组件中对应的值都会变化。或者使用单次绑定v-bind:name.once。

    updateItem: function () {
      for(var i=0;i<this.peoples.length;i++){
          if(this.peoples[i][this.keyColumn] == this.item[this.keyColumn]){
              for(var key in this.item){
                  this.peoples[i][key] = this.item[key];
              }
              break;
          }
      }
      this.$broadcast('showDialog', false);
      this.item = {};
    },
    

    6.其他
    源码地址如下:
    https://github.com/shijingjing07/vue_demo
    还实现了根据关键字查找,防止主键重复等功能。

  • 相关阅读:
    一个诡异的COOKIE问题
    PHP与JAVA构造函数的区别
    PHP获取上个月最后一天的一个容易忽略的问题
    jquery屏幕滚动计算事件总结
    Javascript 代理模式模拟一个文件同步功能
    Javascript实现HashTable类
    Javacript实现字典结构
    Javascript正则对象方法与字符串正则方法总结
    一个app,多个入口图标,activity-alias实现多程序入口并显示指定view完成
    javascript「篱式」条件判断
  • 原文地址:https://www.cnblogs.com/shijingjing07/p/8394527.html
Copyright © 2020-2023  润新知