2018年第29周-快速地在老項目中使用vue的經驗

原有項目使用vue的痛點

前端技術的發展可謂突飛猛進,更有甚者,在deno開源項目的issue中發「求不要更新了,老子學不動了」,這新聞傳遍中國的技術圈子,有人說這是中國人的恥辱。這裏我就不評論好壞。但可見,前端發展的速度很是驚人。
但「存在即合理」,黑格爾的這句話,在技術領域更加是。可以發展的技術,必定更人們帶來便利。擴大解決問題的範圍,或者是提升解決需求的速度等等。
然而對於後臺人員,面對遺留下來的後臺系統,並無徹底先後端分離,也有公司只有後臺人員,先後端都幹。那麼問題來了,上述這種狀況下如何提升效率呢。引入Angular、React、Vue是能解決效率問題,得益於其MVVM技術將視圖UI和業務邏輯分開等四大特性:css

  1. 低耦合。視圖(View)能夠獨立於Model變化和修改,一個ViewModel能夠綁定到不一樣的"View"上,當View變化的時候Model能夠不變,當Model變化的時候View也能夠不變。
  2. 可重用性。你能夠把一些視圖邏輯放在一個ViewModel裏面,讓不少view重用這段視圖邏輯。
  3. 獨立開發。開發人員能夠專一於業務邏輯和數據的開發(ViewModel)。
  4. 可測試。界面素來是比較難於測試的,而如今測試能夠針對ViewModel來寫。

上述特性是否是抽象,前端人員都以爲前端技術發展之快,後端人員就更難接觸和體會。vue官網的例子更是以webpack等模塊化例子來說解,這樣以來,若是想使用vue的好處而已,還要去了解webpack、AMD等等,這讓後端人員再三地望而卻步。
除了技術棧的限制,項目時間也是個門檻,雖然我以爲前端不少思想都是源自於後端的思想,如模塊化,mvc,構建技術等,但學起來仍是要時間呢。老闆並不會給時間開發人員去把整個前端推倒了重幹。推倒重幹也不切實際,一成本高,二風險大(如能不能完成,或能不能趕在市場機會面前完成)。因此漸進地改變是比較穩妥的(保守主義)。html

因此這裏分享下我在老項目快速應用vue的經驗。前端

vue經驗

在原有有項目的html頁面裏,引入vue的依賴vue

<!-- Vue.js v2.5.16 -->
<script src="/js/vue/vue.min.js"></script>

<!-- vue-resource v1.5.1 用於ajax請求-->
<script src="/js/vue/vue-resource.min.js"></script>

本例子是一個添加用戶表單的提交,就只有使用幾個屬性 v-model,v-for和v-on:click,以及{{}}佔位符
此時html代碼只需修改以下(專一於展現):node

<div class="form-horizontal" method="post" id="userFrom">
                        <div class="form-group">
                            <input type="text" class="form-control" id="name" placeholder="請輸入用戶帳號"  v-model="name" >
                        </div>
                        <div class="form-group">
                            <input type="password" class="form-control" id="name" placeholder="請輸入用戶密碼"  v-model="name" >
                        </div>
                        <div class="form-group">
                            <button type="button" class="btn btn-success"  data-toggle="modal" data-target="#myModal">選擇角色</button>
                            <table class="table table-hover" >
                                <thead>
                                <tr>
                                    <th>操做</th>
                                    <th>角色ID</th>
                                    <th>角色名稱</th> 
                                </tr>
                                </thead>
                                <tbody>

                                <tr v-for="(item,index)  in nodeList">
                                    <td>
                                        <button type="button" class="btn btn-danger" v-on:click="remove($event,index)">移除</button>
                                    </td>
                                    <th scope="row">{{ item.id }}</th>
                                    <td>{{ item.name }}</td> 
                                </tr>
                                
                                </tbody>
                            </table>
                        </div>
                        <div class="form-group">
                            <textarea   placeholder="請輸入備註"  name="remark" id="remark"  v-model="remark"></textarea>
                        </div>
                        <div class="form-group">
                            <div class="col-xs-2">
                                <button class="btn btn-primary btn-block btn-flat" v-on:click="createUser">添加</button>
                            </div>
                        </div>
</div>


                     <!-- 彈出框,選擇角色,上面的選擇角色按鈕則彈出如下對話框,這個是boostra技術的範疇,但不影響vue的使用 -->
                    <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
                        <div class="modal-dialog">
                            <div class="modal-content">
                                <div class="modal-header">
                                    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">
                                        &times;
                                    </button>
                                    <h4 class="modal-title" id="myModalLabel">
                                        選擇角色
                                    </h4>
                                </div>
                                <div class="modal-body">
                                    <table class="table table-hover" id="toChooseTable">
                                        <thead>
                                        <tr>
                                            <th>操做</th>
                                            <th>角色ID</th>
                                            <th>角色名稱</th>
                                        </tr>
                                        </thead>
                                        <tbody>
                                            <tr v-for="(item,index) in toChooseList">
                                                <td>
                                                    <button type="button" class="btn btn-danger" v-on:click="choose($event,index)">選擇</button>
                                                </td>
                                                <th scope="row">{{ item.id }}</th>
                                                <td>{{ item.name }}</td>
                                            </tr>
                                        </tbody>
                                    </table>
                                </div>
                                <div class="modal-footer">
                                    <button type="button" class="btn btn-default" data-dismiss="modal">關閉
                                    </button>
                                </div>
                            </div><!-- /.modal-content -->
                        </div><!-- /.modal -->
                    </div>

script代碼修改(專一於數據及其操做)webpack

<script > 
    //提交表單中的數據及操做
    var userFrom = new Vue({
        el: '#userFrom',
        data: {
            name:'',
            password:'',
            remark:'',
            roleList: [],
            apiUrl: '/user/add'
        },
        // 在 `methods` 對象中定義方法
        methods: {
            remove: function (event,index) {
                //移除角色
                //1.將未被選擇的角色數據放回彈出框內
                pushToChooseList(this.roleList[index]);
                
                //2.在已選擇的角色table裏移除這個角色數據
                this.roleList.splice(index,1);
            },
            createUser: function() {
                var params = {
                    name:this.name,
                    password:this.password,
                    remark:this.remark,
                    roleList:[]
                };

                for(var i=0;i<this.roleList.length;i++){
                    var role={};
                       role.id = this.roleList[i].id;
                    role.name = this.roleList[i].name; 
                    params.roleList.push(node);
                }

                this.$http.post(this.apiUrl,JSON.stringify(params),{
                    emulateJSON:false
                }).then(function(response){
                    // response.data中獲取ResponseData實體
                    console.log(response);
                },function(response){
                    // 發生錯誤
                    console.log(response);
                });
            }
        }
    })
    
    //彈出框數據及操做
     var toChooseTable = new Vue({
        el: '#toChooseTable',
        data: {
            toChooseList: [
            ],
            apiUrl: '/role/list'
        },
        // 在 `methods` 對象中定義方法
        methods: {
             loadData: function() {
                 //加載角色數據
                this.$http.post(this.apiUrl, {}).then(function (response) {
                    var result = response.data;
                    for (var i = 0; i < result.data.length; i++) {
                        var role = {};
                        role.id = result.data[i].id; 
                        role.name = result.data[i].name; 
                        toChooseTable.toChooseList.push(node);
                    }

                }, function () {
                    console.log('failed');
                });
            },
            choose: function (event,index) 
                //選擇角色
                //1.將選擇的角色數據放入被選中的table裏
                pushChoosedList(this.toChooseList[index]); 
                //2.移除已被選擇的彈出框的角色數據
                this.toChooseList.splice(index,1);
            }
        }
    })
    //加載角色數據
    toChooseTable.loadData();
    
    
    function pushChoosedList(data) {
        for(j = 0,len=userForm.roleList.length; j < len; j++) {
            if(userForm.roleList[j].id==data.id){ 
                return;
            }
        }
        userForm.roleList.push(data);
    }

    function pushToChooseList(data) {
        for(j = 0,len=toChooseTable.toChooseList.length; j < len; j++) {
            if(toChooseTable.toChooseList[j].id==data.id){ 
                return;
            }
        }
        toChooseTable.toChooseList.push(data);
    }
 
</script>

上述例子很好的展現視圖層和數據層的分離,視圖和數據層都是單獨分開寫的,不知道你能不能從中體會到效率的提升。之前這種彈出框選中數據,在table列表中展現,但是要寫好多js代碼,需手工建立tr標籤,而後再append進table標籤等,還要遍歷定位標籤,反正寫個頁面都老半天。有了vue,這效率簡直大大的提升了。web

element-ui經驗

上述例子中,咱們體會到視圖層和數據層的分離,但還不是很理解模塊化複用,如下就舉個模塊化複用好處的例子,就是使用element-ui的列表及分頁。ajax

引入element-ui
在上述vue基礎上,引入:npm

<!-- 引入樣式 -->
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <!-- 引入組件庫_element-ui@2.4.4@element-ui,官網不提供直接下載,需用cnpm i element-ui -S下載,而後複製lib目錄 -->
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>

只須要引入element-ui的table組件和分頁組件,便可達到複用
修改html代碼:element-ui

<div class="ibox-content" id="content">

                    <!-- table組件 參考:http://element-cn.eleme.io/#/zh-CN/component/table-->
                    <el-table
                            :data="tableData"
                            style="width: 100%">
                        <el-table-column
                                label="日期"
                                width="180">
                            <template slot-scope="scope">
                                <i class="el-icon-time"></i>
                                <span style="margin-left: 10px">{{ scope.row.date }}</span>
                            </template>
                        </el-table-column>
                        <el-table-column
                                label="姓名"
                                width="180">
                            <template slot-scope="scope">
                                <el-popover trigger="hover" placement="top">
                                    <p>姓名: {{ scope.row.name }}</p>
                                    <p>住址: {{ scope.row.address }}</p>
                                    <div slot="reference" class="name-wrapper">
                                        <el-tag size="medium">{{ scope.row.name }}</el-tag>
                                    </div>
                                </el-popover>
                            </template>
                        </el-table-column>
                        <el-table-column label="操做">
                            <template slot-scope="scope">
                                <el-button
                                        size="mini"
                                        @click="handleEdit(scope.$index, scope.row)">編輯</el-button>
                                <el-button
                                        size="mini"
                                        type="danger"
                                        @click="handleDelete(scope.$index, scope.row)">刪除</el-button>
                            </template>
                        </el-table-column>
                    </el-table>

                    <!-- 分頁組件-->
                    <div align="center">
                        <el-pagination
                                @size-change="handleSizeChange"
                                @current-change="handleCurrentChange"
                                :current-page="page"
                                :page-sizes="[10, 20, 30, 40]"
                                :page-size="rows"
                                layout="total, sizes, prev, pager, next, jumper"
                                :total="totalRecord">
                        </el-pagination>
                    </div>
                </div>

修改script代碼

<script >
    /*<![CDATA[*/
    var content = new Vue({
        el: '#content',
        data: {
            tableData: [{
                date: '2016-05-02',
                name: '王小虎',
                address: '上海市普陀區金沙江路 1518 弄'
            }, {
                date: '2016-05-04',
                name: '王小虎',
                address: '上海市普陀區金沙江路 1517 弄'
            }, {
                date: '2016-05-01',
                name: '王小虎',
                address: '上海市普陀區金沙江路 1519 弄'
            }, {
                date: '2016-05-03',
                name: '王小虎',
                address: '上海市普陀區金沙江路 1516 弄'
            }],
            url:'/user/list',
            //搜索條件
            criteria: '',
            //下拉菜單選項
            select: '',
            //默認每頁數據量
            rows: 10, 
            //當前頁碼
            page: 1,
            //查詢的頁碼
            start: 1,
            //默認數據總數
            totalRecord: 1000
        },
        // 在 `methods` 對象中定義方法
        methods: {
            loadData: function(criteria, pageNum, pageSize){
                this.$http.post(this.url,{criteria:criteria, page:pageNum, rows:pageSize},{emulateJSON:true}).then(function(res){
                    var page = res.data; 
                    this.tableData = page.data;
                    this.totalRecord = page.totalRecord;
                },function(){
                    console.log('failed');
                });
            },
            handleEdit: function (index, row) {
                console.log(index, row);
            },
            handleDelete: function (index, row) {
                console.log(index, row);
            },
            //每頁顯示數據量變動
            handleSizeChange: function(val) {
                this.rows = val;
                this.loadData(this.criteria, this.page, this.rows);
            },

            //頁碼變動
            handleCurrentChange: function(val) {
                this.page = val;
                this.loadData(this.criteria, this.page, this.rows);
            }
        }
    })
    //加載數據
    content.loadData(content.criteria, content.page, content.rows);
    /*]]>*/
</script>

雖然沒有使用webpack更完全的模塊化。但上述的列子,也夠給老項目帶來複用的效率提高,後臺人員不用花時間去調樣式。

相關文章
相關標籤/搜索