从我接手到将这个页面代码重构前,一直都仍是使用angular1的代码去作的,需求来了也是用angular去实现;做为一个憧憬新技术的前端,怎么忍受得了如今还在使用这么有历史感的框架,因此,之前就一直在酝酿着如何将angular重构成vue。javascript
这个资讯项目代码总体都是使用angular.js来去实现的,而这次想重构的资讯详情页面只是其中的一个页面,因此新建了一个文件夹/newApp
、做为之后新技术的文件夹,之后使用vue技术的都放在这个文件夹下,区别于原先文件夹/app
。php
在旧的angular1的js文件中,因为页面功能丰富,全部的功能代码全都挤在了同一个js中,这就致使主要的js一共有1500+行的代码。每次打开看到长长的一摞代码、还要在里面找到对应的功能代码,就不由吐槽其中的不合理。。css
因此此次重构,我按照页面中的每一个模块、每一个功能,来将页面拆分红不一样的.vue组件模块,之后想要去维护、或者新增功能时,能够直接去对应的模块文件中修改或者是新增一个vue文件。html
存放着vue的组件代码前端
这个文件夹下,存放着一些能够被复用的组件vue
资讯里面的图片浏览组件、在app内会调用客户端的浏览器组件能力、端外使用第三方组件库photoSwipe的来实现点击浏览大图。java
在这个文件夹下放着一些资讯的业务jsnode
语言包web
资讯页面用到的sass文件、不过因为node-sass的安装有点麻烦(在技术选型时未考虑此状况),后面可能会重构成使用less来作css的预处理器。vuex
一些公用的函数被抽成单独的文件放在这里
评论列表页面主js
评论详情页面主js
使用eventBus来实现页面的通讯
使用vue-i18n来实现页面的多语言
资讯详情页面主js
混入
将分享的逻辑单独抽取成一个js。这里单独抽成一个js是由于,在安卓的webview加载h5时,会等js文件执行完毕以后才渲染出页面(即用户看到东西),因此页面的主js是进行了延迟加载的,可是分享这一逻辑是但愿仍是能提早加载,因此单独将这一功能抽取成一个js,让页面按照顺序正常去加载。
由于将页面按照功能拆分红了不少小的模块,在不一样的模块之间的通讯就须要想方法实现,这些模块之间大可能是一种兄弟组件的关系。
咱们首先能想到的vue中父子组件的通讯功能的实现,可是父子组件的场景不适合如今的多个兄弟组件之间的通讯,或者说实现起来很啰嗦。
因此考虑另外两种方法实现:eventBus和vuex。考虑到资讯详情页只有一个单页面,引入vuex的话可能会过重了,使代码体积增长很多,于是使用了EventBus事件总线这一方法来实现。
在Vue中可使用 EventBus来做为沟通桥梁的概念,就像是全部组件共用相同的事件中心,能够向该中心注册发送事件或接收事件,全部组件均可以上下平行地通知其余组件。
具体作法是在eventBus.js这个文件中建立一个vue对象,而且将其export出去。其实就是建立一个vue对象做为eventBus,使用它的$on
和$emit
来实现。这种设计模式是发布/订阅模式,即pub/sub
。
//eventBus.js
import vue from 'Vue';
export default new Vue();
复制代码
在想要通讯的组件中使用$on
和$emit
方法。
例如,资讯详情页面有一个接口是去请求几个数据:广告、相关个股等。这个接口其实在页面中只须要在初始化时去请求一次,而后将数据保存下来就好。
因此在Main.js中负责去请求这个接口,而后请求回来了,发布一个dataReady
的事件,将数据也带出去。而在其余的、须要用到这个初始化数据的组件就去订阅这个事件,拿到初始化的数据后,就将其render到页面中。
// Main.js
_initData() {
// ****
//使用eventBus广播这个事件,多个子组件中用到了初始化数据
EventBus.$emit('dataReady', data);
}
//adImg.vue 广告模块
mounted() {
EventBus.$on('dataReady', data => {
// *****
})
}
//relatedStock.vue 相关个股模块
mounted() {
Event.$on('dataReady', data => {
// ****
})
}
复制代码
在这里其实有个小优化,能够将直接在Vue的原型上添加一个vue对象实例做为全局的消息总线,就不用每次都去import 一次eventBus.js。
//Main.js
Vue.prototype.$bus = new Vue();
//使用时:
this.$bus.$on('', () => {});
复制代码
在使用eventbus完成项目以后发现,事件总线这一个机制确实很方便,不一样的组件之间能够随意通讯,可是由此很容易形成难以管理的灾难。好比,在某个模块中订阅了某个事件,这个事件是从哪里发布的、何时发布的,在代码中彷佛有点难以搜索发布的时机。
资讯详情页面中实现了其余的一些功能,好比多皮肤、多语言这些特性。
多皮肤,使用了css的预处理器sass来实现,用到了sass的变量、混入指令等特性。
首先让视觉给一个不一样皮肤下的色彩对照表,而后将其写入sass文件中,用变量来保存对应的颜色值。根据外部的class来使用对应的颜色变量。
外面的class则是由后端在渲染html时,将对应的皮肤class添加在最外层的div中,在.vue组件中加入对应的class样式,就能作到随肤、且不闪屏。
不过我一开始在重构时的想法并非经过三组对皮肤的变量来实现,我一开始的想法是在sass里面,就能拿到对应的皮肤的值,从而在使用时都是只须要知道是要哪一个层级的颜色值就能够,而不须要在外部的sass代码里分别写三种。
可是问题在于,没法将js能拿到的皮肤信息传入sass中,这个想了好久也没想到解决方案。若是能在sass中就能够拿到皮肤信息,从而直接赋予元素对应的皮肤值,这样就很方便了。因此这里对sass、less这些语言的局限性也深有感触,它们终究只是一个“预处理器”而已。
多语言特性,使用了vue-i18n这个插件来实现。
其实如今包括资讯详情说是只有一个页面,但因为它具备的评论功能,是能够聚合成一个spa的,包括资讯详情页面(Main.js)、资讯评论列表页面(commentDetailMain.js)、评论详情页面(allCommentsMain.js)。这三个页面用到的技术栈在重构以后很是类似,甚至将公共的组件都已经抽取出来了。可是我在重构时仍是把它们三个当成不一样的页面拆开了,这一点有待改进。
目前是经过mixin这一特性,将三个页面公共的一些东西抽取在其中,分别在三个页面的js中引入这个mixin,能够避免一些重复的东西。
//mixin.js
// 资讯详情页、资讯评论列表页、资讯评论详情页公用的一些东西
import i18n from './i18n';
import ReplyBar from '**/replyBar.vue';
import BannerTop from '**/bannerTop.vue';
import CommentInput from '**/commentInput.vue';
let mixin = {
i18n,
components: {
ReplyBar, //底部悬浮框
BannerTop, //顶部的banner条
CommentInput //评论输入框
}
}
export default mixin;
复制代码
---- 后来又想了下,因为当前模式仍是使用php渲染html的方式,因此无法作成SPA这样子,只能等待加上了node的ssr以后才能实现= =。
因为node-sass的安装有时会出现一些问题,因此仍是使用less做为替代比较稳妥..
在打包时将vue中的样式文件也打进js中了,须要在打包时将其抽取出来
进行ing...