1、TodoContainer組件

  TodoContainer組件,用來組織其它組件,這是react中推薦的方式,也是redux中高階組件一般就是用來包裝成容器組件用的,比如redux中的connect函數(shù),返回的包裝組件就是一個容器組件,它用來處理這樣一種場景:加入有A、B兩個組件,A組件中需要通過Ajax請求和后端進行交互;B組件也需要通過Ajax請求和后端交互,針對這種場景有如下代碼:

seo優(yōu)化培訓,網(wǎng)絡(luò)推廣培訓,網(wǎng)絡(luò)營銷培訓,SEM培訓,網(wǎng)絡(luò)優(yōu)化,在線營銷培訓

//組件A定義var CompA={
    template:'<div>A 渲染 list</div>',
    data:function(){        return {
            list:[]
        }
    },
    methods:{
        getListA:function(){
            $.ajax({
                url:'xxx',
                dataType:'json',
                success:r=>this.list=r.data
            })
        }
    }
};//組件B定義var CompB={
     template:'<div>B 渲染list</div>',
    data:function(){        return {
            list:[]
        }
    },
    methods:{
        getListB:function(){
            $.ajax({
                url:'xxx',
                dataType:'json',
                success:r=>this.list=r.data
            })
        }
    }
}

seo優(yōu)化培訓,網(wǎng)絡(luò)推廣培訓,網(wǎng)絡(luò)營銷培訓,SEM培訓,網(wǎng)絡(luò)優(yōu)化,在線營銷培訓

可以看出,A組件和B組件中都會存在Ajax訪問重復(fù)代碼,有重復(fù)代碼就要提取出來;第一種方式,提取公共方法,使用mixin混入到兩個組件中,所謂混入就是動態(tài)把方法注入到兩個對象中;

第二種方法使用外部傳入,這是react中推薦的方式,使用props傳入;其實我們仔細分析我們的兩個組件,都是為了渲染列表數(shù)據(jù),至于是在組件外請求還是在組件內(nèi)請求,它是不關(guān)注的,這樣我們可以進一步考慮,把AB組件重構(gòu)成只用來渲染數(shù)據(jù)的pure組件,數(shù)據(jù)由外部傳入,而vue正好提供了這種props父傳子的機制,把Ajax操作定義到父組件中(就是我們這里提到的容器組件),也起到了重復(fù)代碼提取的作用,基于此請看我們的第二版代碼:

seo優(yōu)化培訓,網(wǎng)絡(luò)推廣培訓,網(wǎng)絡(luò)營銷培訓,SEM培訓,網(wǎng)絡(luò)優(yōu)化,在線營銷培訓

//A組件var CompA={
    template:'<div>A</div>',
    props:['list']
};//B組件var CompB={
     template:'<div>B</div>',
     props:['list']
}//容器組件var Container={
    template:`        <comp-a :list="listA" ></comp-a>
        <comp-b :list="listB" ></comp-b>    `,
    components:{        'comp-a':CompA,        'comp-b':CompB
    },
    methods:{
        getListA:function(){            //TODO:A 邏輯        },
        getListB:function(){            //TODO:B 邏輯        }
    }
}

seo優(yōu)化培訓,網(wǎng)絡(luò)推廣培訓,網(wǎng)絡(luò)營銷培訓,SEM培訓,網(wǎng)絡(luò)優(yōu)化,在線營銷培訓

這樣A、B組件變成了傻白甜組件,只是負責數(shù)據(jù)渲染,所有業(yè)務(wù)邏輯由容器組件處理;容器組件把A、B組件需要的數(shù)據(jù)通過props的方式傳遞給它們。

已經(jīng)明白了容器組件的作用,那么我們來實現(xiàn)一下前幾篇中todolist的容器組件吧,上篇已有基本結(jié)果,這里先出代碼后解釋:

seo優(yōu)化培訓,網(wǎng)絡(luò)推廣培訓,網(wǎng)絡(luò)營銷培訓,SEM培訓,網(wǎng)絡(luò)優(yōu)化,在線營銷培訓

/**
     * 容器組件
     * 說明:容器組件包括三個字組件     */
    var TodoContainer = {
        template: `        <div class="container">
            <search-bar @onsearch="search($event)"></search-bar>
            <div class="row">
                <todo-list :items="items" @onremove="remove($event)" @onedit="edit($event)"></todo-list>            
                <todo-form :init-item="initItem" @onsave="save($event)" ></todo-form>
            </div>
        </div>    `,
        data: function () {            return {                /**
                 * Todolist數(shù)據(jù)列表
                 * 說明:通過props傳入到Todolist組件中,讓組件進行渲染                 */
                items: [],                /**
                 * TodoForm初始化數(shù)據(jù)
                 * 說明:由于TodoForm包括兩種操作:新增和編輯;新增操作無需處理,編輯操作需要進行數(shù)據(jù)綁定,這里通過傳入initItem屬性進行編輯時數(shù)據(jù)的初始化
                 * 如果傳入的值為空,說明為新增操作,由initItem參數(shù)的Id是否為空,來確認是更新保存還是新增保存                 */
                initItem: {
                    title: '',
                    desc: '',
                    id: ''
                }
            }
        },
        components: {            'search-bar': SearchBar,/**SearchBar組件注冊 */
            'todo-form': TodoForm,/**TodoForm組件注冊 */
            'todo-list': todoList/**TodoList組件注冊 */
        },
        methods: {            /**
             * 模擬保存數(shù)據(jù)方法
             * 輔助方法             */
            _mock_save: function (lst) {
                list = lst;
            },            /**
             * 根據(jù)id查詢對象
             * 輔助方法             */
            findById: function (id) {                return this.items.filter(v => v.id === id)[0] || {};
            },            /**
             * 查詢方法
             * 由SearchBar組件觸發(fā)             */
            search: function ($e) {                this.items = list.filter(v => v.title.indexOf($e) !== -1);
            },            /**
             * 保存方法
             * 響應(yīng)新增和更新操作,由TodoForm組件觸發(fā)             */
            save: function ($e) {                //id存在則為編輯保存
                if (this.initItem.id) {                    var o = this.findById($e.id);
                    o.title = $e.title;
                    o.desc = $e.desc;
                } else {                    this.items.push(new Todo($e.title, $e.desc));
                }                this.initItem = { id: '', title: '', desc: '' };                this._mock_save(this.items);
            },           /**
            * 刪除方法
            * 響應(yīng)刪除按鈕操作
            * 由TodoItem組件觸發(fā)            */
            remove: function ($e) {                this.items = this.items.filter(v => v.id !== $e);                this._mock_save(this.items);
            },            /**
             * 編輯按鈕點擊時,進行表單數(shù)據(jù)綁定             */
            edit: function ($e) {                this.initItem = this.findById($e);
            }
        }
    }

seo優(yōu)化培訓,網(wǎng)絡(luò)推廣培訓,網(wǎng)絡(luò)營銷培訓,SEM培訓,網(wǎng)絡(luò)優(yōu)化,在線營銷培訓

  我們把所有業(yè)務(wù)邏輯也放在容器組件中處理,其它組件都是傻白甜,這樣的好處是,其它組件容易重用,因為只是數(shù)據(jù)渲染,并不涉及業(yè)務(wù)操作,這種組件沒有業(yè)務(wù)相關(guān)性,比如一個list組件我可以用它顯示用戶信息,當然也可以用它顯示角色信息,根據(jù)傳入的數(shù)據(jù)而變化。

  對上述代碼,需要簡單解釋一下的是,Vue中父子event傳遞是通過$emit和$on來實現(xiàn)的,但是寫法和angular中有一些差異;在angular中我們一般這樣寫:

seo優(yōu)化培訓,網(wǎng)絡(luò)推廣培訓,網(wǎng)絡(luò)營銷培訓,SEM培訓,網(wǎng)絡(luò)優(yōu)化,在線營銷培訓

//事件發(fā)射$scope.$emit("onxxx",data);//事件監(jiān)聽$scope.$on("onxxx",function(e,data){   //TODO: })

seo優(yōu)化培訓,網(wǎng)絡(luò)推廣培訓,網(wǎng)絡(luò)營銷培訓,SEM培訓,網(wǎng)絡(luò)優(yōu)化,在線營銷培訓

但是在vue中$on是直接使用v-on:onxxx或@onxxx來寫的,所以一般存在的是這樣的代碼:

  <todo-list :items="items" @onremove="remove($event)" @onedit="edit($event)"></todo-list>            
  <todo-form :init-item="initItem" @onsave="save($event)" ></todo-form>

其它代碼中加入了很多注釋,也比較簡單,就不做過多解釋了,有疑問可提交。

2、SearchBar組件

  SearchBar組件比較簡單,只是簡單觸發(fā)查詢按鈕,發(fā)射(觸發(fā))onsearch事件,然后TodoContainer組件中使用 @onsearch="search($event)" 進行監(jiān)聽。

seo優(yōu)化培訓,網(wǎng)絡(luò)推廣培訓,網(wǎng)絡(luò)營銷培訓,SEM培訓,網(wǎng)絡(luò)優(yōu)化,在線營銷培訓

 /**
     * 搜索組件     */
    var SearchBar = {
        template: `        <div class="row toolbar">
            <div class="col-md-8">
                keyword:                <input type="text" v-model="keyword" />
                <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);
            }
        }

    }

seo優(yōu)化培訓,網(wǎng)絡(luò)推廣培訓,網(wǎng)絡(luò)營銷培訓,SEM培訓,網(wǎng)絡(luò)優(yōu)化,在線營銷培訓

3、TodoForm組件

  TodoForm組件,是我們Todolist中的表單組件,編輯和新增公用,我們需要考慮的是,我們的初始化數(shù)據(jù)由外部傳入,首先看第一版代碼,考慮有什么坑?

seo優(yōu)化培訓,網(wǎng)絡(luò)推廣培訓,網(wǎng)絡(luò)營銷培訓,SEM培訓,網(wǎng)絡(luò)優(yōu)化,在線營銷培訓

 
     TodoForm =<div class="col-md-6">
        <div class="form-inline">
            <label ="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 ="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="ok()" class="btn btn-primary offset-md-10"  />
        </div>
    </div>'initItem'.$emit('onsave',

seo優(yōu)化培訓,網(wǎng)絡(luò)推廣培訓,網(wǎng)絡(luò)營銷培訓,SEM培訓,網(wǎng)絡(luò)優(yōu)化,在線營銷培訓

這段代碼有什么問題呢?我們把傳入的初始化參數(shù)給了我們的todo對象,這樣導(dǎo)致的直接問題是:新增的時候沒問題,但是編輯的時候無法綁定數(shù)據(jù),原因是,編輯操作實際上就是修改外部傳入的initItem對象,但是todo只在組件初始化的時候被賦值,其它時候是不響應(yīng)initItem變化的,如何才能響應(yīng)initItem變化,很明顯是我們的computed屬性,computed屬性會響應(yīng)其封裝對象的變化;代碼第二版修改如下:

seo優(yōu)化培訓,網(wǎng)絡(luò)推廣培訓,網(wǎng)絡(luò)營銷培訓,SEM培訓,網(wǎng)絡(luò)優(yōu)化,在線營銷培訓

 
     TodoForm =<div class="col-md-6">
        <div class="form-inline">
            <label ="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 ="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="ok()" class="btn btn-primary offset-md-10"  />
        </div>
    </div>'initItem' { id: .initItem.id, title: .initItem.title, desc: .$emit('onsave',

seo優(yōu)化培訓,網(wǎng)絡(luò)推廣培訓,網(wǎng)絡(luò)營銷培訓,SEM培訓,網(wǎng)絡(luò)優(yōu)化,在線營銷培訓

 

 4、TodoList && TodoItem組件

  TodoList組件是數(shù)據(jù)列表組件,它的每一個列表項我們進行了一次封裝,每一個list中的列表項,就是一個TodoItem組件,所以在TodoItem組件中,只需要引入todoitem數(shù)據(jù)即可,唯一需要關(guān)注的就是todoItem組件中會觸發(fā)onremove和onedit事件。

seo優(yōu)化培訓,網(wǎng)絡(luò)推廣培訓,網(wǎng)絡(luò)營銷培訓,SEM培訓,網(wǎng)絡(luò)優(yōu)化,在線營銷培訓

/**
     * 列表項組件     */
    var TodoItem = {
        template: `     <tr>
        <th>{{todo.id}}</th>
        <td>{{todo.title}}</td>
        <td>{{todo.desc}}</td>
        <td>
            <input type="button" value="remove" @click="remove()" class="btn btn-danger" />
            <input type="button" value="edit" @click="edit()" class="btn btn-info" />
        </td>
    </tr>    `,
        props: ['todo'],
        methods: {
            edit: function () {
                console.log(this.todo);                this.$emit('onedit', this.todo.id);
            },
            remove: function () {                this.$emit('onremove', 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"  @onedit="edit($event)" @onremove="remove($event)"></todo-item>
        </table>
    </div>    `,
        props: ['items'],
        components: {            'todo-item': TodoItem
        },
        methods: {
            edit: function ($e) {                this.$emit('onedit', $e);
            },
            remove: function ($e) {                this.$emit('onremove', $e);
            }
        }
    }

seo優(yōu)化培訓,網(wǎng)絡(luò)推廣培訓,網(wǎng)絡(luò)營銷培訓,SEM培訓,網(wǎng)絡(luò)優(yōu)化,在線營銷培訓

http://www.cnblogs.com/Johnzhang/p/7223064.html