首先,我们先了解什么是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){
          this.detail.view = transition.to.params.view
        }else{
          this.detail.view = ''
        }
        if(this.ready){
          this.detailview(this.detail.id,this.detail.view)
        }
      }
    },
  }

</script>





Logo

前往低代码交流专区

更多推荐