vue组件化案例

简单的vue 组件化demo,效果很简单,就是一个列表增删改查。

未组件化代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>demo1</title>
    <script src="https://cdn.bootcss.com/vue/2.4.1/vue.js"></script>
    <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="stylesheet">

</head>

<body class="container">
<div id="app">
    <div class="row toolbar">
        <div class="col-md-8">
            keyword:
            <input type="text" v-model="keyword" placeholder="title"/>
            <input type="button" @click="query()" value="search" class="btn btn-primary"/>
        </div>
    </div>
    <div class="row" style="margin-top: 10px;">
        <div class="col-md-6">
            <table class="table table-bordered">
                <tr>
                    <th></th>
                    <th>title</th>
                    <th>desc</th>
                    <th></th>
                </tr>
                <tr v-for="(todoItem,index) in todolist">
                    <td>{{todoItem.id}}</td>
                    <td>{{todoItem.title}}</td>
                    <td>{{todoItem.desc}}</td>
                    <td>
                        <input type="button" value="remove" @click="remove(index)" class="btn btn-danger"/>
                        <input type="button" value="editor" @click="editor(todoItem.id)" class="btn btn-info"/>
                    </td>
                </tr>
            </table>
        </div>
        <div class="col-md-6">
            <div class="form-inline">
                <label for="title" class="control-label col-md-4">title:</label>
                <!--<input type="text" v-model="title" class="form-control col-md-8">-->
                <input type="hidden" v-bind:value="todoItem.id"/>
                <input type="text" v-model="todoItem.title" class="form-control col-md-8">
            </div>
            <div class="form-inline">
                <label for="desc" class="control-label col-md-4">desc</label>
                <!--<input type="text" v-model="desc" class="form-control col-md-8">-->
                <input type="text" v-model="todoItem.desc" class="form-control col-md-8">
            </div>
            <div class="form-inline">
                <input type="button" value="OK" v-on:click="save()" class="btn btn-primary offset-md-10"
                       :disabled="canSave"/>

            </div>
        </div>
    </div>
</div>
<script>
    var list = [];
    var todoItem = (function () {
        var id = 1;
        return function (title, desc) {
            this.title = title;
            this.desc = desc;
            this.id = id++;
        }
    })();

    new Vue({
        el: '#app',
        data: {
            todolist: [],
            todoItem: {
                id: '',
                title: '',
                desc: ''
            },
            keyword:''
        },
        methods: {
            save: function () {
                if (this.todoItem.id) {
                    //编辑修改
                    var obj = this.todolist.filter(v => v.id === this.todoItem.id)[0];
                    obj.title = this.todoItem.title;
                    obj.desc = this.todoItem.desc;
                } else {
                    //保存数据
                    this.todolist.push(new todoItem(this.todoItem.title, this.todoItem.desc))
                }
                //初始化输入框
                this.todoItem = {title: '', desc: ''};

                list = this.todolist;
            },
            editor: function (id) {
                var obj = this.todolist.filter(v => v.id === id)[0];
                this.todoItem = {
                    id: obj.id,
                    title: obj.title,
                    desc: obj.desc
                }
            },
            remove: function (index) {
                this.todolist.splice(index, 1);
                list = this.todolist;
            },
            query:function(){
                //过滤title中不包含keyword的数据
                //这里必须通过list全局变量过滤,而不能通过this.todolist,因为需要给this.todolist赋值,赋值后无法还原原来的列表。
                this.todolist = list.filter(v => v.title.indexOf(this.keyword) !== -1);
            }
        },
        computed:{
            //过滤
            canSave: function () {
                return !this.todoItem.title || !this.todoItem.desc
            }
        }
    })
</script>
</body>
</html>

效果:


image.png

组件化后:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>demo1组件化</title>
    <script src="https://cdn.bootcss.com/vue/2.4.1/vue.js"></script>
    <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="stylesheet">
</head>
<body class="container">
<div id="app">
    <todo-container></todo-container>
</div>

<script>
;(function () {
    var list = [];
    var Todo = (function () {
        var id = 1;
        return function (title, desc) {
            this.title = title;
            this.desc = desc;
            this.id = id++;
        }
    })();

    //搜索框
    var SearchBar = {
        template : `<div class="row toolbar">
                        <div class="col-md-8">
                            keyword:
                            <input type="text" v-model="keyword" placeholder="title"/>
                            <input type="button" @click="search()" value="search" class="btn btn-primary"/>
                        </div>
                    </div>`,
        data:function(){
            return{
                keyword:''
            }
        },
        methods:{
            search:function(){
                this.$emit('onsearch',this.keyword);
            }
        }
    };

    //表单
    var TodoForm = {
        template : `<div class="col-md-6">
                        <div class="form-inline">
                            <label for="title" class="control-label col-md-4">title:</label>
                            <input type="hidden" v-bind:value="todo.id"/>
                            <input type="text" v-model="todo.title" class="form-control col-md-8">
                         </div>
                         <div class="form-inline">
                            <label for="desc" class="control-label col-md-4">desc:</label>
                            <input type="text" v-model="todo.desc" class="form-control col-md-8">
                        </div>
                        <div class="form-inline">
                            <input type="button" value="OK" v-on:click="save()" class="btn btn-primary offset-md-10"/>
                        </div>
                     </div>`,
        props:['initItem'],
        computed:{
            todo:function(){
                return {id:this.initItem.id,title:this.initItem.title,desc:this.initItem.desc}
            }
        },
        methods:{
            save:function(){
                this.$emit('onsave',this.todo);
            }
        }
    };

    //列表项组件
    var TodoItem = {
        template : `<tr>
                        <td>{{todo.id}}</td>
                        <td>{{todo.title}}</td>
                        <td>{{todo.desc}}</td>
                        <td>
                            <input type="button" value="remove" @click="remove()" class="btn btn-danger"/>
                            <input type="button" value="editor" @click="editor()" class="btn btn-info"/>
                        </td>
                    </tr>`,

        props:['todo'],
        methods:{
            remove:function(){
                this.$emit('onremove',this.todo.id)
            },
            editor:function(){
                this.$emit('oneditor',this.todo.id)
            }
        }

    };

    //列表组件
    var TodoList = {
      template : `
        <div class="col-md-6">
            <table class="table table-bordered">
                <tr>
                    <th></th>
                    <th>title</th>
                    <th>desc</th>
                    <th></th>
                </tr>
               <todo-item v-for="item in items" :todo="item" :key="item.id" @onremove="remove($event)" @oneditor="editor($event)"></todo-item>
            </table>
        </div>
       `,
        props:['items'],
        components:{
          'todo-item':TodoItem
        },
        methods:{
            remove:function($e){
                this.$emit('onremove',$e)
            },
            editor:function($e){
                this.$emit('oneditor',$e)
            }
        }
    };


    //主组件
    //主组件中,通过:items和:init-item将数据传递到子组件中,子组件通过props接受并直接使用;通过@onsearch,@onremove,@ondeitor,@onsave,将对应操作事件的逻辑传递给子组件,子组件通过$emit接收并返回操作执行后的结果到主组件上进行显示
    var TodoContainer = {
        template : `<div id="container">
                        <search-bar @onsearch="search($event)"></search-bar>
                        <div class="row" style="margin-top:10px;">
                            <todo-list :items="items" @onremove="remove($event)" @oneditor="editor($event)"></todo-list>
                            <todo-form :init-item="initItem" @onsave="save($event)"></todo-form>
                        </div>
                    </div>`,
        data: function () {
            return {
                items: [],
                initItem: {
                    title: '',
                    desc: '',
                    id: ''
                }
            }
        },
        components: {
            'search-bar': SearchBar,
            'todo-list': TodoList,
            'todo-form': TodoForm
        },
        methods: {
            /**
             * 模拟保存数据方法
             * 辅助方法
             */
            _mock_save: function (lst) {
                list = lst
            },
            /**
             * 根据id查询对象
             * 辅助方法
             */
            findById: function (id) {
                return this.items.filter(v => v.id === id)[0] || {};
            },
            /**
             * 查询方法
             * 由SearchBar组件触发
             */
            search: function ($e) {
                this.items = list.filter(v => v.title.indexOf($e) !== -1);
            },
            /**
             * 保存方法
             * 响应新增和更新操作,由TodoForm组件触发
             */
            save: function ($e) {
                if (this.initItem.id) {
                    //更新
                    var obj = this.findById($e.id);
                    obj.title = $e.title;
                    obj.desc = $e.desc;
                } else {
                    //新增
                    this.items.push(new Todo($e.title,$e.desc))
                }
                //重置
                this.initItem = {
                    title: '',
                    desc: '',
                    id: ''
                };
                //更新数据列表
                this._mock_save(this.items)
            },
            /**
             * 删除方法
             * 响应删除按钮操作
             * 由TodoItem组件触发
             */
            remove:function($e){
                this.items = this.items.filter(v => v.id !== $e)
                this._mock_save(this.items)
            },
            /**
             * 编辑按钮点击时,进行表单数据绑定
             */
            editor:function($e){
                this.initItem = this.findById($e);
            }
        }
    };

    var app = new Vue({
        el: '#app',
        components: {
            'todo-container': TodoContainer
        }
    });
})();
</script>
</body>
</html>

效果:


image.png

详细见解请移步原贴:http://www.cnblogs.com/Johnzhang/p/7208682.html#3787902

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,363评论 25 707
  • 目录 UI组件 开发框架 实用库 服务端 辅助工具 应用实例 Demo示例 UI组件 element★13489 ...
    余生社会阅读 19,654评论 7 233
  • 期年缘与初遇,滋言以触心意。 适而顾及新年,继而不及倾城。 或此生死与共,或此不若滋言。 无言无语口拙,不紧不慢心疲。
    凉小阅读 368评论 0 1
  • 什么是领导者 这是一个非常简单的问题 简单到大家都忽略了 反而就不简单了 在许多人的观念中 领导者是在职务范围内 ...
    弘慧阅读 364评论 0 0