赞
踩
这是我在工作中开发的一个微信端的h5项目,主要功能是一个答题以及一个调用微信扫描查看一些机器设备信息,功能不多,但麻雀虽小,五脏俱全,vue中常用的技术栈都有涉及到。这篇文章主要是对此项目的一个总结以及对整个项目的开发流程做一个梳理。
这个项目我是使用vue技术栈进行开发,之前我大部分的工作是开发微信小程序,vue虽然也用过,不过项目经验还是偏少,也就是写了一些demo,所以这次的项目我打算使用vue进行开发,根据需求以及设计,感觉使用vue并没有太大问题,功能其实也并不复杂,所以直接先使用vue-cli创建一个项目再说,然后把一些初始代码给删除,并把可能会使用到的一些库装上。项目大概使用的技术栈如下:
vue + vue-router + vuex + axios + scss + 其他
基本上都是常用的那一套,vuex在这个项目中用的不是很多,但是我还是不嫌麻烦的用了,其实这个项目本身不是很大很复杂,所以我在这里使用vuex其实不是很必要,但是想了一下,能用的就直接都用上吧,但大家不要学啊,我这里主要是为了自己实践vue的项目开发,所以并不在意麻不麻烦了。直接就用了。
既然整体的技术栈以及确定下来,那么之后就是组织项目结构了,这一点,其实在我看来还是很重要的,因为项目结构的组织在一定程度上意味着你这个项目的逻辑或者功能的划分,意味着你对这个项目是如何进行拆分构建的,我觉得这个可以值得我们去花时间研究一下的。我的这个项目的src目录结构如下(主要就是src目录):
大致解释一下吧:
api:用于存放后台接口请求,里面存放着axios的配置文件以及根据逻辑、功能划分的不同后台接口api接口模块。
assets:这个就不用多说了,存放着js,scss,image文件这些静态资源文件
baseComponent:这个是根据vue官方文件中对于组件描述的一些最佳编写的,里面存放一些全局的功能组件,以Base开头,配合下面的registerBaseComponent.js进行这些基础组件的全局注册,这样你就可以在项目中任何地方直接使用,而无需重新引入。ps:这一块的组件和项目业务逻辑没有任何关联,在编写基础组件时也不要和你的业务逻辑产生任何关联。
components:这个存放你这个项目中可复用的公共组件,每个项目根据业务的不同会编写不同的components,而上面的baseComponents则可能复用于每个项目,因为他不和业务耦合。而components则根据每个项目的业务逻辑进行编写的可复用组件。
mixins:一般组件中可能会存在重复的功能,比如扫码功能,我这个项目会调用微信的扫码,而且在不同的地方会同时使用这个功能,但是扫码在页面上的展示形式不一样(有的是点击按钮,有的是点击图片),但功能是一致的,所以可以把扫码这个功能作为一个qcodeMixin,不同的组件需要这个功能时,直接通过组件的mixins字段引入即可(虽然这个扫描也可以作为一个功能模块而不一定要mixins,不过在此只是为了说明一下mixins的作用)。这是作为逻辑和功能层面的一个代码复用的方法。展示层使用组件进行复用即可。
service:项目的业务逻辑层,注意,我在api中只是只是处理了数据接口,比如接口错误处理,接口返回的统一格式化处理以及一些接口的加密处理(这个项目有抽奖,所以进行了接口数据加密),并没有将业务逻辑也编写在api里面,api只处理接口相关的事宜,而真正使用接口,并处理业务逻辑是在serviec中进行的,根据不同的业务需求,service分为了不同的功能模块,用于处理不同的业务逻辑。他会对不同的接口进行调用并处理接口返回的数据,他只对数据层面的业务逻辑进行封装,而其他的通用功能模块,你可以根据是否会复用编写至mixins中,或者作为一个模块编写至assets的js中。
store:这个没什么好说的,和vuex相关的,比如getters,state,mutations,actions文件存放的地方
view:里面存放着vue的页面组件,里面的每一个组件都是作为项目的一个页面存在的,他和下面的router.js这个vue路由中配置进行一一对应的。
main.js和App.vue:这个没什么好说的,项目入口,都有的。
router.js:vue路由
以上所展示的大致就是这个项目的结构,是我目前为止所考虑到的目录结构,可能会有不足或者不合理的地方,不过这是我目前所理解的,或者说我会的一种项目结构组织了,他可能会随着我不断的学习从而有更好的项目组织方式,不过,我一开始刚入门时,可能项目估计也是只分js,css,html,image这几个文件夹就没了,然后我慢慢的学会去如何组织我的项目结构,看别人项目结构,找百度,自己一次一次的尝试,不说现在这个他可能有多好,但至少对比我之前的项目结构来说,我认为现在这个是好的。最后提一嘴,项目结构的组织真的我觉得是比较重要的,大家要重视一下。
说完了项目结构,那现在说一说我在项目中,学会了哪些项目实践方法,也在这里记录一下:
我在编写微信小程序的时候,就开始留意公共组件的编写了,这样我在不同的微信小程序开发的时候就可以复用这些基础组件,而不必在此重新编写,即使有不同,也是需要更改样式,因为他和具体的业务逻辑无关,在使用vue时,我也把微信小程序中的一些基础组件以及根据vue中的一些场景自己编写了一套自己vue基础组件,比如说对话框,类似微信小程序中的toast提示框,按钮,加载中提示,以及顶部导航栏,底部tabbar,以及在网上找的一个移动端页面滚动组件better-scroll等等。这些东西你可以在不同的vue项目中可能都会使用到,他和业务逻辑无关,即使需要修改,也仅仅是修改样式,交互逻辑并无太大差别。当然了,自己开发的和一些优秀的组件库所开发的肯定要差一些,但是,这不是重点,当你不用组件库时,这些基础组件就可以派上用场,而且找bug也不会那么困难,重要的是你要尝试去自己编写组件,这会帮助你提示自己的水平,而且你自己编写一遍,然后再去看别人怎么编写的,这会解决你在自己编写组件时的一些疑惑,帮助你知道如何怎样才可以编写出更好的组件出来,比如我在编写顶部导航栏时...
空位:例子,导航栏的消息传递解决。
所以,有空不妨自己实现一些组件,虽然看似无用,因为网上有更优秀的组件库,但是如果出发点不一样,那结果也会不一样,如果你是抱着学习,抱着了解组件编写的思维,为了更好编写组件的,而不是为了自己写自己用的,那么你总会有收获。
空位:myvue中的readme中的一些最佳实践。
移动端适配,我这里使用的是rem,适配方案使用的是一个flex.js,但是,有时候把,自己写rem真的有点麻烦,所以,需要一个将px转化为rem的postcss编译插件,也就是postcss-px2rem,还有一点,这个postcss-px2rem插件无法指定忽略一些忽略文件,比如node_modules中的一些vue插件会自带css样式,而且很有可能这个插件使用的是px为单位,那么如果你把它进行rem转换了,那大小会变小很多,我就碰到了这个问题,查了一些资料,改为使用一个叫postcss-px2rem-exclude的插件,这个插件他可以设置忽略哪些文件不需要进行rem编译,就可以解决这个问题。
我偶尔发现页面在真机上可以自由的放大缩小,遂查了一下资料,发现原来是vue生成的meta头的问题,将原本vue-cil自动生成的适用移动端的meta头改为如下设置即可:
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
我这个项目做的是微信端的,有些手机在页面跳转了几次后,底部会出现一栏白条,用于页面的前进后退,询问了一个同事,他说是因为我在vue的页面跳转时使用的push进行路由跳转,导致history中增加了历史记录,从而有些手机会产生底部的导航栏进行前进后退,解决办法就是全部使用replate进行路由跳转,使history中始终只有一条,从而阻止白条的出现,但是也无法使用手机自带的返回键进行页面前进和后退,所以使用时进行权衡利弊吧。
vue-router的历史记录模式,怎么说呢,需要后台进行配合,当后台需要服务器找不到文件,也就是404时,让服务器始终返回我这个vue项目的index页面,如果不这样做的话,服务器就真的返回404了,因为vue-router中的路由所指的url在真实服务器上是不存在的,所以如果你使用history模式,切记和你的后台沟通一下,而如果用户真的访问一个404资源,你可以在你的router配置中设置一个404资源提示即可。通常会配置一个 * 的通配符路由,这个通常就是404页面,如果vue-router在匹配不到你配置的实际路由时,总会匹配到这个通配符,所以,你直接在这里配置404提示页面即可。
vue配置的webpack(我用的3.0的cli),默认没有配置图片压缩,所以你需要自行配置图片压缩loader来进行图片压缩操作。这里我使用的是image-webpack-loader,在vue-config.js里面进行配置即可,就和你自己使用webpack配置图片压缩时一样。但是,需要注意的是,你可以使用函数来进行配置这个图片压缩(cli支持函数配置),因为图片压缩比较耗时,比较慢,你在开发环境就不需要压缩图片了,只在生产环境进行图片压缩即可。
我在项目结构中单独使用一个文件夹来存放mixis对象,用于业务逻辑之间的代码复用,其实我在一些可复用的组件之中也编写了组件之间的components,比如对话框组件,对话框可能不止一种,有几种形式,但是他也会有一些公共的方法,比如取消,确定,控制对话框的显示隐藏的属性等等这些东西,也可以作为一个mixins,所以mixins不止是在业务逻辑之间使用,组件之间也可以考虑在一些情况下进行使用。
还有,mixins在编写时,mixins只需要实现自己的职责中的事情就行了,并且如果这个mixins中的一些操作有时需要执行其他的逻辑,比如在完成自身功能后需要做一些其他事,即使这件事真的都不会变,那么你也很有必要再多编写一个函数方法来执行这件事,这样你可以给使用这个mixins的组件一个机会,一个扩展其他功能的机会,一个可以自定义行为的机会,一个可以重写这件事的机会,而不是写死这一段逻辑。
其他的东西
我在使用微信jssdk时,因为之前没有使用过,所以遇到了一些问题,比如签名错误,无法监听到分享什么的就不说了,百度找一找就可以了,虽然让我感觉挺头疼的,不过我要说的是另外一个关于微信jssdk的需求,也就是在vue不同的路由页面设置不同的分享内容以及不同的分享链接,因为这个页面时使用vue编写的单页面应用,所以不能只设置一次微信jssdk的分享内容就可以分享不同的页面,所以需要在两个不同的(我这个项目只有两个页面路由需要设置不同的分享内容)页面设置不同的分享内容,我的做法是在App.vue中监听 $route 数据的变化,从而,再根据不同的路由,设置不同的分享内容即可。当然,有一些小问题需要注意的,比如在页面第一次进入时,设置分享内容需要设置在wx.ready的回调函数中,而如果微信jssdk以及配置完成,那么就可以直接使用wx.onMenuShareAppMessage进行设置了。还有,我做了为频繁修改微信分享内容做了一点小优化(可能优不优化影响不大),那就是只有在涉及到需要自定义分享内容页面的路由改变时,才重新设置微信分享内容,因为两个不需要设置特定分享内容的页面之间的跳转,根本没有必要重新再设置一遍wx.onMenuShareAppMessage,没有必要,所以我在这里做了过滤。虽然不过滤影响也不大就是了。
这一个就是经验问题了,之前没怎么用过axios,所以踩到这个坑了,这个问题其实各位上百度找一下即可,这里就不啰嗦了,我找了篇文章传送门给你们吧:https://blog.csdn.net/csdn_yudong/article/details/79668655
vue-router 切换同一个路由(只是路由参数改变了,比如params),然后导致组件复用,页面不会更新,这个坑也比较场景的,我这个项目主要出现在扫描查看设置信息那里,也就是在一个设备信息页面中扫描另一个设备,页面不更新,所以,需要在这个页面监听$route的变化,然后重新执行执行一些初始化操作即可。还有一个就是需要注意的点,那就是使用我提到的移动端页面滚动插件better-srcoll时,因为这个插件是模拟的滚动条,而不是真正的浏览器滚动条,所以,vue-router的滚动功能没有效果的,需要你自行设置better-srcoll的滚动位置。
我们知道,我们在改变js,css,图片这些文件时,webpack打包后会产生一个hash来标识文件改动,然后让浏览器强制更新缓存,这个在js,css和图片中是没有问题的,也可以正常工作,但是,还有一个问题就是出在index.html上,每次在其他文件改动时,index.html中引入的资源也会改动,比如app.js这些,而index.html本身确没有改动,导致浏览器还是延用之前的index.html文件,然后也还是引用的旧的app.js文件,结果就是要么是因为缓存,页面没有改动,要么就是报404,因为之前的打包后的文件已经被删除了,那么该怎么解决呢?当然了,这也和我这个项目的地址是直接暴露index.html文件有关咯,真实的话,我猜想,应该是项目对外暴露的url地址一般是不变的,然后后台根据访问,查找这个index.html文件进行返回,然后,在后台设置这个http的header头为不缓存此文件,那么每次获取的就是最新的index.html文件了。
安卓的页面的input在获取焦点时,导致页面整个window窗口变小,从而 可能会使input被覆盖或者被顶上去。(具体要看布局)反正,这不是我们想要的,那改如何解决呢?一般我们是使用监听window.resize来进行处理的,因为移动端网页在手机的键盘弹起时,会导致window窗口的reisze事件被触发,因为window窗口在键盘弹起时,确实被缩小到大约只剩一半了,那么我们就可以在window.resize在被触发时,设置这个input元素的位置,这里根据不同的布局需要做一些计算,而且以防止其他事件导致window的resize被触发(比如ios底部的导航栏也就是白条出现),所以需要设置一个临界值,比如只有在window的高度相比正常时的高度少了300时,我们才假定键盘被弹起了,此时再做处理。除此之外,我们还需要在这个页面被销毁时,移除这个事件,以防止内存泄露,这通常在你为全局对象绑定了事件时(比如window对象)是个好习惯,切记。
在默认的vue-cli中,资源的打包路径是以绝对路径开始设置的,如果你的资源确实是直接放在一个域名之下,那么你可以不用管,比如你打包后的文件直接放在www.xxxx.com下的,那么打包后的资源也确实会从这个域名的根路径开始查找,这是ok的,但是,如果你的资源是放在一个域名的子路径下面,比如:www.xxx.com/xxx/....那么,这时候,以根路径作为资源就不对了,会报404,那如何解决呢?在vue-cli3.0中你可以配置publicPath,你可以使用设置他,让webpack以相对路径来打包你的js,css,img等资源,如下:vue-config.js
- module.exports = {
- publicPath: './',
- configureWebpack: {
- // ...
- }
- }
如果你需要使用cdn,那么你只需要设置publicPath为你的cdn的路径即可。
这里为什么需要提一下日志的记录呢,之前我是一般也不会做这个的,但是在我使用微信jssdk时,偶尔有时候会出现jssdk配置失败的问题,但是苦于生产环境,又是处在微信内置浏览器导致无法定位原因,所以,我就感觉有必要做一个日志的记录,在微信jsskd配置失败时,也就是err时,将失败原因以及此时的一些参数记录在日志中,发送给后台,以便定位和查找原因,从而解决问题,之前也没怎么在意过这种事情,不过现在想想,还是觉得有必要的,在可能出错的地方使用日志来记录错误,这样可以优化你的程序。
以上这些记录的是比较可见的问题,还有一些其他的不太具有描述性的问题和场景就没有写出来,不过这个项目让我对vue的开发还是有很大的提示的,我相信,之后再使用vue开发时,这些我遇到的坑应该就不会再难倒我了,我没遇到的,以后遇到了再去解决就是了,在项目编写的过程中,一些经验以及感悟,都是最重要的收获。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。