认识Vue.js+Vue.js的优缺点+和与其他前端框架的区别
首先,我们先了解什么是MVX框架模式?MVX框架模式:MVC+MVP+MVVM1.MVC:Model(模型)+View(视图)+controller(控制器),主要是基于分层的目的,让彼此的职责分开。View通过Controller来和Model联系,Controller是View和Model的协调者,View和Model不直接联系,基本联系都是单向的。用户User通过控制器Controller来
首先,我们先了解什么是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>
更多推荐
所有评论(0)