1. 程式人生 > >認識Vue.js+Vue.js的優缺點+和與其他前端框架的區別

認識Vue.js+Vue.js的優缺點+和與其他前端框架的區別

首先,我們先了解什麼是MVX框架模式?

MVX框架模式:MVC+MVP+MVVM

1.MVC:Model(模型)+View(檢視)+controller(控制器),主要是基於分層的目的,讓彼此的職責分開。

View通過Controller來和Model聯絡,Controller是View和Model的協調者,View和Model不直接聯絡,基本聯絡都是單向的。

使用者User通過控制器Controller來操作模板Model從而達到檢視View的變化。

2.MVP:是從MVC模式演變而來的,都是通過Controller/Presenter負責邏輯的處理+Model提供資料+View負責顯示。

在MVP中,Presenter完全把View和Model進行了分離,主要的程式邏輯在Presenter裡實現。

並且,Presenter和View是沒有直接關聯的,是通過定義好的介面進行互動,從而使得在變更View的時候可以保持Presenter不變。

MVP模式的框架:Riot,js。

3.MVVM:MVVM是把MVC裡的Controller和MVP裡的Presenter改成了ViewModel。Model+View+ViewModel。

View的變化會自動更新到ViewModel,ViewModel的變化也會自動同步到View上顯示。

這種自動同步是因為ViewModel中的屬性實現了Observer,當屬性變更時都能觸發對應的操作。

MVVM模式的框架有:AngularJS+Vue.js和Knockout+Ember.js後兩種知名度較低以及是早起的框架模式。

Vue.js是什麼?

看到了上面的框架模式介紹,我們可以知道它是屬於MVVM模式的框架。那它有哪些特性呢?

其實Vue.js不是一個框架,因為它只聚焦檢視層,是一個構建資料驅動的Web介面的庫。

Vue.js通過簡單的API(應用程式程式設計介面)提供高效的資料繫結和靈活的元件系統。

Vue.js的特性如下:

1.輕量級的框架

2.雙向資料繫結

3.指令

4.外掛化

Vue.js與其他框架的區別?

1.與AngularJS的區別

相同點:

都支援指令:內建指令和自定義指令。

都支援過濾器:內建過濾器和自定義過濾器。

都支援雙向資料繫結。

都不支援低端瀏覽器。

不同點:

1.AngularJS的學習成本高,比如增加了Dependency Injection

特性,而Vue.js本身提供的API都比較簡單、直觀。

2.在效能上,AngularJS依賴對資料做髒檢查,所以Watcher越多越慢。

Vue.js使用基於依賴追蹤的觀察並且使用非同步佇列更新。所有的資料都是獨立觸發的。

對於龐大的應用來說,這個優化差異還是比較明顯的。

2.與React的區別

相同點:

React採用特殊的JSX語法,Vue.js在元件開發中也推崇編寫.vue特殊檔案格式,對檔案內容都有一些約定,兩者都需要編譯後使用。

中心思想相同:一切都是元件,元件例項之間可以巢狀。

都提供合理的鉤子函式,可以讓開發者定製化地去處理需求。

都不內建列數AJAX,Route等功能到核心包,而是以外掛的方式載入。

在元件開發中都支援mixins的特性。

不同點:

React依賴Virtual DOM,而Vue.js使用的是DOM模板。React採用的Virtual DOM會對渲染出來的結果做髒檢查

Vue.js在模板中提供了指令,過濾器等,可以非常方便,快捷地操作DOM。

如何使用Vue.js?

1.安裝

(1)script

如果專案直接通過script載入CDN檔案,程式碼示例如下:

<script src="http://webapp.didistatic.com/static/webapp/shield/z/vue/vue/1.0.24/vue.min.js"></script>

(2)npm

如果專案給予npm管理依賴,則可以使用npm來安裝Vue,執行如下命令:

$npm i vue --save-dev

(3)bower

如果專案基於bower管理依賴,則可以使用bower來安裝Vue,執行如下命令:

$bower i vue --save-dev

2018.4.24====================好久沒寫部落格。(太多知識需要整理,從今天開始,有時間就寫博,分享開發過程中的點滴)附上一個最基本的vue元件頁面。

<template>
<!--app-actions start-->
<div class="app-actions row">
    <ul class="btn-list">
      <li v-if="permissions.create" :disabled='quota.totalSecurityGroupsUsed >= quota.maxSecurityGroups'>
        <a href="javascript:;" class="btn btn-primary"
@click="action_modal = 'Create'"><i class="icon icon-i446 pr5"></i>{{
          $t('access_security.create') }}</a>
      </li>
      <li
v-if="permissions.edit || permissions.delete">
        <v-dropdown>
          <button type="button" class="btn btn-info btn-icon dropdown-toggle"
data-toggle="dropdown">
            <i class="icon icon-i692"></i>
          </button>
          <ul slot="dropdown-menu" class="dropdown-menu">
            <li :class="{'disabled': !acSingle || !menu.edit}"
v-if="permissions.edit"><a href="javascript:;"
@click="action_modal = 'Edit'">{{
              $t('base.edit')}}</a></li>
            <li :class="{'disabled': !acMulti}" v-if="permissions.delete"><a
class="danger" href="javascript:;"
@click="action_modal = 'Delete'">{{ $t('base.delete')}}</a>
            </li>
          </ul>
        </v-dropdown>
      </li>
      <li>
        <button type="button" class="btn btn-info btn-icon" @click="ajaxData">
          <i class="icon icon-i500"></i></button>
      </li>
    </ul>
<!--當前頁面資料檢索-->
<div class="app-search">
      <input type="text" class="form-control app-search-input" v-model="searchKey" placeholder="{{ $t('base.search_name')}}" maxlength="64">
      <i class="icon icon-i441"></i>
    </div>
  </div>
<!--app-actions end-->
  <!--app-body start-->
<div class="app-body row">
    <v-grid
:overall="false"
:count="COUNT"
:titles="grid.titles"
:items="LIST"
:transname="grid.name"
:checkeds.sync="checkeds"
:orderkey.sync="grid.order_key"
:orderitem="grid.order_item"
:orderswitch.sync="grid.order_switch"
:ready="ready"
>
      <div class="grid-canvas" slot="grid-canvas">
        <div class="grid-row" v-for="security_group in LIST | orderBy grid.order_key grid.order_switch"
:class="{'selected': checkeds.indexOf(security_group.id) !== -1}">
          <div class="grid-cell row-key"><input type="checkbox"
value="{{security_group.id}}"
v-model="checkeds"></div>
          <div class="grid-cell r0">
            <a v-link="{ name: routeDetail, params: { id:security_group.id , view:detail_view }}">
{{security_group.name_cn}}
            </a>
          </div>
          <div class="grid-cell r1">{{security_group.description}}</div>
        </div>
      </div>
    </v-grid>
<!--detailView start-->
<v-detailview :show.sync="detail.show" :itemdata.sync="detail.item"
:backurl="routeGrid">
      <v-tabs slot="detail-body" :active="detail.view" :router="routeDetail"
v-bind:classname="['detailTabs']" v-ref:tabs>
        <v-tab :header="$t('volumes.description')" controls="description"
v-if="true">
          <c-description :data="detail.item"></c-description>
        </v-tab>
      </v-tabs>
    </v-detailview>
<!--detailView end-->
</div>
<!--app-body end-->
  <!--=======================action modal start=============================-->
<div role="dialog" v-show="action_modal != null" transition="fade"
class="modal in">
    <component :is="action_modal" transition="zoom"
:item="ACTIVE_ITEM"></component>
  </div>
<!--=======================action modal end=============================-->
  <!--=======================action modal start=============================-->
<div role="dialog" v-show="rules_modal != null" transition="fade" class="modal in">
    <component :is="rules_modal" :item="ACTIVE_ITEM" :direction="direction" transition="zoom"></component>
  </div>
<!--=======================action modal end=============================-->
</template>
<script>
import { networksAjax } from '../../../ajax.js'
import { extend,statusFilter,filterSearchKey} from '../../../lib/function.js'
import vDropdown from '../../../lib/strap/Dropdown.vue'
import vGrid from '../../../lib/strap/Grid.vue'
import vDetailview from  '../../../lib/strap/Detailview.vue'
import vTabs from '../../../lib/strap/Tabsetview.vue'
import vTab from '../../../lib/strap/Tab.vue'
import Create from './action_create.vue' //彈出層create元件
import Edit from './action_edit.vue' //彈出層edit元件
import Delete from './action_delete.vue' //彈出層delete元件
import Createrules from './action_create_rules.vue' //彈出層createrules元件
import cDescription from './detail_security_groups.vue' //彈出層description元件
export default {
    components: {
      vDropdown,
vGrid,
vDetailview,
vTabs,
vTab,
Create,
Edit,
Delete,
Createrules,
cDescription
    },
data(){
      return {
        menu:{//設定選單選項初始值
'create':true,
'edit':true,
'delete':true
},
routeDetail:'security_groups_view', //側拉路由name
routeGrid:'access_security', //主列表路由name
AJAX_API:this.$resource( '', {}, networksAjax),//資料介面
DATA:[],//資料來源
COUNT:0, //資料條目總數
searchKey:'', //搜尋篩選值
searchField:['name_cn'],//搜尋欄位
action_modal:null,
rules_modal:null,
checkeds:[], //已選擇資料id
ready:false, //資料是否已經載入
//是否多選(toolbar判斷用)
acMulti:false,
//是否單選(toolbar判斷用)
acSingle:false,
detail:{
          show:false,//側拉元件開關
id:null,//側拉id
item:{}, //側拉顯示物件
view:null,//側拉顯示標籤
},
quota:{
          totalSecurityGroupsUsed:0,
maxSecurityGroups:10
},
detail_view:'description', //側拉預設選項卡
grid:{
          name:'access_security', //當前grid翻譯對應值
titles:['name','description'],//grid列表元件列表標題
order_item:['name','description'], //傳入允許使用排序功能的列的title 例如order_item:['name','size','type'],
order_key: null,//列表排序欄位
order_switch: null,//列表正反切換
},
direction:null,//側拉詳情中-上行下行
permissions:COS.permissions.resource_console.access_security.security_groups
}
    },
computed: {
      LIST:{
        get: function(){
          this.DATA.forEach(item => {
            item['name_cn'] = item.name == 'default' ? this.$t('access_security.default') : item.name})
          return filterSearchKey(this.DATA,this.searchField,this.searchKey)
        }
      },
//根絕LIST的篩選&checkeds選中專案計算
ACTIVE_ITEM: {
        get: function(){
          let items = []
          const dataList = this.LIST
const checkeds = this.checkeds;
for(let n=0; n<dataList.length; n++){
            for(let i=0; i<checkeds.length; i++){
              if(dataList[n].id == checkeds[i]){
                items.push(dataList[n])
              }
            }
          };
return items;
}
      }
    },
watch: {
      //剔除本地篩選後的checkeds
'LIST': function(val) {
        let new_data = [];
for(let n=0; n<this.checkeds.length; n++){
          for(let i=0; i<val.length; i++){
            if(val[i].id.indexOf(this.checkeds[n]) >= 0){
              new_data.push(this.checkeds[n])
            }
          }
        }
        this.checkeds = new_data;
},
'detail.id':function () {
        if(this.detail.show==true){
          let arr=[];
for(var k in this.$refs.tabs.renderData){
            arr.push(this.$refs.tabs.renderData[k].controls)
          }
          if(Array.indexOf(arr,this.detail_view)==-1){
            this.detail.view=arr[0]
          }
        }
      },
//根據選中id獲取相應資料物件
'checkeds': function (items) {
        //多選邏輯
if(items.length == 0){//無勾選
this.$router.replace({name:this.routeGrid})//返回主頁面
this.acMulti = false;
this.acSingle = false;
}else if(items.length > 1){//多選
this.$router.replace({name:this.routeGrid})//返回主頁面
this.acMulti = true;
this.acSingle = false;
}else{
          this.acMulti = true;
this.acSingle = true;
}
      },
'ACTIVE_ITEM':function(val){
        if(val.length == 1 && val[0].name == 'default'){
          this.menu.edit = false;
}else{
          this.menu.edit = true;
}
      },
//資料載入完成後監測是否展示
'ready': function(val){
        if(val){this.detailview(this.detail.id,this.detail.view)}
      }
    },
ready() {
        //載入資料
this.ajaxData()
        this.getQuotas()
    },
methods: {
      //獲取列表資料
ajaxData(){
        this.ready = false;
this.AJAX_API.security_groups().then((response) => {
          // success callback
this.DATA = response.data.data
this.COUNT = response.data.data.length
this.ready = true
}, (response) => {
          // error callback
if(typeof response.data.message =="string"){
            this.$dispatch('notice_msg', {msg:response.data.message,type:'info',duration:5})
          }else if(typeof response.data.message =="object"){
            for(var k in response.data.message){
              this.$dispatch('notice_msg', {msg:k+' '+response.data.message[k],type:'info',duration:5})
            }
          }
        })
      },
//根據路由控制detailview顯示
detailview(id,view){
        if(id){
          //根據ID找到對應物件
for(let i=0; i<this.LIST.length; i++){
            if(this.LIST[i].id == id){
              this.detail.show = true
              this.checkeds = []
              this.checkeds.push(id)
              this.detail.item = this.LIST[i]
            }
          }
        }else{
          this.detail.show = false
          this.detail.item = {}
        };
},
getQuotas:function(){
        this.AJAX_API.get_security_groups_quotas().then((response) => {
            // success callback
if(response.data.code == 0){
              this.quota = response.data.data
}
          }, (response) => {
            // error callback
if(typeof response.data.message =="string"){
              this.$dispatch('notice_msg', {msg:response.data.message,type:'danger',duration:5})
            }else if(typeof response.data.message =="object"){
              for(var k in response.data.message){
                this.$dispatch('notice_msg', {msg:k+' '+response.data.message[k],type:'danger',duration:5})
              }
            }
          })
      }
    },
events: {

      //socketIO更新
'IO_networks':function (data) {
        if(data.option == 'reload'){
          this.AJAX_API.get({'id':data.resource_id}).then((response) => {
            // success callback
const DATA = this.DATA;
for(let i=0; i<DATA.length; i++) {
              if (DATA[i].id == data.resource_id) {
                extend(DATA[i],response.data.data,true)
              }
            }
          }, (response) => {
            // error callback
if(typeof response.data.message =="string"){
              this.$dispatch('notice_msg', {msg:response.data.message,type:'danger',duration:5})
            }else if(typeof response.data.message =="object"){
              for(var k in response.data.message){
                this.$dispatch('notice_msg', {msg:k+' '+response.data.message[k],type:'danger',duration:5})
              }
            }
          })
          this.$dispatch('notice_msg', {msg:this.$t('base.volumes') +' "' + data.name + '" ' + this.$t('volumes.status_info.'+ data.state),type:'info',duration:5})
        }else if(data.option == 'delete'){
          const DATA = this.DATA;
for(let i=0; i<DATA.length; i++) {
            if (DATA[i].id == data.resource_id) {
              this._delete_update_list(DATA[i].id)
              this.ajaxData()
            }
          }
          this.$dispatch('notice_msg', {msg:this.$t('base.volumes') +' "' + data.name + '" ' + this.$t('volumes.status_info.'+ data.state),type:'info',duration:5})
        }else{
          const DATA = this.DATA;
for(let i=0; i<DATA.length; i++) {
            if (DATA[i].id == data.resource_id) {
              DATA[i].status = data.state;
}
          }
          this.$dispatch('notice_msg', {msg:this.$t('base.volumes') +' "' + data.name + '" ' + this.$t('volumes.status_info.'+ data.state),type:'info',duration:5})
        }
      }
    },
//根據路由獲取ID/VIEW
route: {
      data (transition) {
        this.detail.id = transition.to.params.id
if(transition.to.params.view){