基于Vue2全家桶的移动端AppDEMO实现
pusong0
8年前
<p>好久没更新过Vue的小文章,上次做了一个基于Vue+Mint-ui的移动端AppDemo,集成了推送功能,然后通过cordova打包生成apk,移动端表现还不错,今天把这个小东西分享出来,希望有更多的小伙伴能够用Vue去做一些有意思的东西,本人才疏学浅,有说的不对的地方,还请大家多多指教。下面按照惯例放上demo地址和源码地址,希望大家能给我点下star:</p> <p><a href="/misc/goto?guid=4959735669783438229" rel="nofollow,noindex">Demo</a> (进去需要先注册才能登录,用的localstorage,随便写符合格式的就行)</p> <p><a href="/misc/goto?guid=4959735669878572965" rel="nofollow,noindex">Demo基于Vue2源码</a></p> <p><a href="/misc/goto?guid=4959735669959379539" rel="nofollow,noindex">Demo基于Vue1的源码</a></p> <h2>搭建项目</h2> <h3>项目结构</h3> <p>本项目才用Vue-cli脚手架自动生成,这是一个Vue生态系统中一个伟大创举。这意味着我们不需要手动构建我们的项目,而它就可以很快地为我们生成。下图是一个完整的项目结构,如图所示:</p> <p><img src="https://simg.open-open.com/show/d24a63d4698acc363a107b8bf7cabc63.jpg"></p> <ul> <li> <p>components:包含所有的页面组件</p> </li> <li> <p>vuex:包含vuex相关文件</p> </li> <li> <p>modules:存放每个页面单独的state和mutation</p> </li> <li> <p>static:静态文件存放(图片和图标库等)</p> </li> <li> <p>index.html:渲染的页面</p> </li> <li> <p>main.js:应用入口点,包含根实例</p> </li> <li> <p>App.vue:主页面组件</p> </li> </ul> <h2>项目流程:</h2> <ul> <li> <p>安装Vue-cli(要有node与npm)</p> </li> </ul> <pre> <code class="language-xml">npm i -g vue-cli</code></pre> <ul> <li> <p>创建一个webpack项目,并且下载依赖</p> </li> </ul> <pre> <code class="language-xml">vue init webpack vue-demo-orderApp cd vue-demo-orderApp npm i</code></pre> <ul> <li> <p>安装Vue-router,Vuex和Mint-ui</p> </li> </ul> <pre> <code class="language-xml">npm install vue-router vuex --save npm install mint-ui --save</code></pre> <ul> <li> <p>热加载打开页面(生产的时候运行 npm run build )</p> </li> </ul> <pre> <code class="language-xml">npm run dev</code></pre> <p>项目的框架已经搭建好了,接下来就是为项目添砖加瓦。</p> <h2>页面结构分析</h2> <p><img src="https://simg.open-open.com/show/afabd1f790016bc889b5a0dcc0b6a8cc.png"></p> <p>--</p> <p>本项目为一个demo项目,主要为了练习vue2的使用,结构上借鉴了官方的写法,界面为通用的app样式,才用饿了么团队的Mint-Ui的制作。</p> <p>这个demo的每一个页面都是一个.vue文件,利用Vue的单文件组件,非常便于管理每个页面的状态,样式和数据,首页主要是展示页,和操作面板页。下面是主页的代码:</p> <pre> <code class="language-xml"><template> <div class="index-container"> <!-- 轮播图部分 --> <mt-swipe :auto="4000"> <mt-swipe-item><div class="banner1 banner" style="background:url('./static/banner1.jpg');background-size: cover;"></div></mt-swipe-item> <mt-swipe-item><div class="banner2 banner" style="background:url('./static/banner2.jpg');background-size: cover;"></div></mt-swipe-item> </mt-swipe> <!-- 订单同步状态部分 --> <mt-popup class="status" v-model="popupVisible" popup-transition="popup-fade" position="top"> 同步{{ orders_status }} </mt-popup> <!-- 首页功能栏部分 --> <ul class="icon-list"> <li class="icon"> <router-link to="order" class="iconlink"></router-link> <img src="../assets/scan.png" class="clear"> <h4>订单管理</h4> <p>扫描盘点,手工盘点</p> <i></i> </li> <li class="icon"> <router-link to="goods" class="iconlink"></router-link> <img src="../assets/ana.png" class="clear"> <h4>渠道管理</h4> <p>扫描盘点,手工盘点</p> <i></i> </li> <li class="icon"> <router-link to="order" class="iconlink"></router-link> <img src="../assets/store.png" class="clear"> <h4>订单发布</h4> <p>扫描盘点,手工盘点</p> <i></i> </li> <li class="icon" @click="getOrders()"> <router-link to="test" class="iconlink"></router-link> <img src="../assets/goods.png" class="clear"> <h4>订单同步</h4> <p>快速同步渠道订单,方便快捷</p> <i></i> </li> <li class="icon"> <router-link to="personinfo" class="iconlink"></router-link> <img src="../assets/download.png" class="clear"> <h4>个人中心</h4> <p>信息管理,logo更换</p> <i></i> </li> </ul> </div> </template> <script type="text/javascript"> import { MessageBox } from 'mint-ui' import { mapState } from 'vuex' export default{ created:function(){ if(window.localStorage.user == null){ this.$router.push({path: '/login'}) } }, data(){ let popupVisible = false let orders_status return {popupVisible, orders_status} }, computed:mapState({ orders_status: state => state.news.orders_status, }), methods:{ getOrders: function(){ const that = this this.$store.dispatch('synchroOrder', this).then(function(){ that.popupVisible = true }) } } } </script></code></pre> <p>先看代码部分Vue2相比Vue1相比还是变化很多的,首先就是计算属性比以前更好用了,其次是生命周期部分和以前相比变化很大,这点要注意下。其次是Vue2更推崇ES6的写法,并且支持了promise,这是非常好的地方,而且官方的迭代文档也写的很全,基本上很容易从1迭代到2。并且Vue2不再支持双向绑定(sync)这个方法了,它使用了一种更好的方式来进行父子组件之间的通信(emit),这样子组件就不会影响到父组件的状态。下面我放出这个主页Vue1的代码,大家可以比较一下:</p> <pre> <code class="language-xml"><template> <div class="index-container"> <mt-swipe :auto="4000"> <mt-swipe-item><div class="banner1 banner" style="background:url('./static/banner1.jpg');background-size: cover;"></div></mt-swipe-item> <mt-swipe-item><div class="banner2 banner" style="background:url('./static/banner2.jpg');background-size: cover;"></div></mt-swipe-item> </mt-swipe> <ul class="icon-list"> <li class="icon"> <img src="../assets/scan.png" class="clear"> <h4>订单管理</h4> <p>扫描盘点,手工盘点</p> <i></i> </li> <li class="icon"> <img src="../assets/ana.png" class="clear"> <h4>渠道管理</h4> <p>扫描盘点,手工盘点</p> <i></i> </li> <li class="icon"> <img src="../assets/store.png" class="clear"> <h4>订单发布</h4> <p>扫描盘点,手工盘点</p> <i></i> </li> <li class="icon" @click="getOrders(this)"> <img src="../assets/goods.png" class="clear"> <h4>订单同步</h4> <p>快速同步渠道订单,方便快捷</p> <i></i> </li> <li class="icon"> <img src="../assets/download.png" class="clear"> <h4>个人中心</h4> <p>信息管理,logo更换</p> <i></i> </li> </ul> <mt-popup :visible.sync="popupVisible" popup-transition="popup-fade" position="top"> 同步成功</mt-popup> </div> </template> <script type="text/javascript"> import { synchroOrder } from '../vuex/action' import { MessageBox } from 'mint-ui' export default{ init:function(){ if(window.localStorage.user == null){ //window.location.href = window.location.origin + window.location.pathname + '#!/login' console.log('请登录') this.$router.go({path:'/login'}) } }, data(){ let popupVisible = false return {popupVisible} }, vuex:{ getters:{ order_status: state => state.orders_status }, actions:{ synchroOrder } }, methods:{ getOrders: function(that){ this.synchroOrder(that) if(this.order_status){ this.popupVisible = !this.popupVisible } } } }</code></pre> <p>上面的代码比较可以看出,VueX和Vue-router的变化也很大,这里我就详细说这两者的变化了,有啥问题可以讨论讨论,大概说下,首先是Vue-router部分,不再支持以前V-link的这种方式了,变为采用router-link这种方式。VueX方面我感觉变化最大的就是写法和以前不一样了。Vuex才用 this.$store.dispatch('xxx') 来派发一个action,通过commit委托给mutation来执行相应的操作,并且支持异步的写法,就是ES6的promise,给一段官方的异步写法:</p> <pre> <code class="language-xml">actions: { actionA ({ commit }) { return new Promise((resolve, reject) => { setTimeout(() => { commit('someMutation') resolve() }, 1000) }) } }</code></pre> <p>。还有一个明显的变化是mapActions和mapState属性,mapActions可以用来指明一个组件的方法去调用store.dispatch()方法。通过mapState属性我们可以去定义一些计算函数和键值对,主要是为了方便运用多个states属性和getters。还有一个比较大的变化就是Vuex2可以支持将store转变为Module的写法,来更细致的去管理状态。我的这个小demo也用上了这个新特性,它能让大型的页面也能有很好的状态管理。</p> <p>可以对比一下同一个项目基于Vue1和Vue2的写法。这样更能够直观的去了解到不同之处,并且可以去细想一下作者为什么这个改,这对我们编程思想的提示是很有帮助的。</p> <h2>基于模块化的Vuex</h2> <p><img src="https://simg.open-open.com/show/77437c3499162174bd336c8533810ed6.png"></p> <p>将不同的Vuex状态放在对应的页面状态模块里,这样当需要管理的数据很多的时候也能从容的应对。</p> <p>可以看下这里面是怎么写的,下面是news.js里面的:</p> <pre> <code class="language-javascript">import * as types from '../mutation-types' const state = { news:{}, orders_status: '成功', selected:'首页' } const mutations = { [types.SYNCHRO_ORDER](state, items){ state.news = items console.log(state.news.length) if(state.news.length != 0){ state.orders_status = '成功' } else{ state.orders_status = '失败' } }, [types.CHANGE_SELECTED](state, item){ state.selected = item } } export default{ state, mutations }</code></pre> <p>下面是mution-types.js</p> <pre> <code class="language-xml">export const CHANGE_ORDER = 'CHANGE_ORDER' export const CHANGE_STATUS = 'CHANGE_STATUS' export const DISPLAY_STATUS = 'DISPLAY_STATUS' export const CHANGE_PERSON = 'CHANGE_PERSON' export const SYNCHRO_ORDER = 'SYNCHRO_ORDER' export const CHANGE_POP = 'CHANGE_POP' export const CHANGE_SELECTED = 'CHANGE_SELECTED'</code></pre> <p>可以看到我们将所有的mutaions方法都放在了mution-types里面进行统一的管理,然后再对应的模块里面来处理这些方法,在不同的模块里面我们只能操作对应模块的数据和状态,这对于状态管理来说简直是非常完美。</p> <p> </p> <p>来自:https://segmentfault.com/a/1190000008213141</p> <p> </p>