项目名称
树洞(tree-hole)
项目背景
有些话不适合对任何人说,何不对着树洞发泄一下。
树洞的想法源自于一个朋友对知己的看法,最初设计有一点像漂流瓶。不过,这样的想法有一点傻。如果要严格匹配出一个知己需要大量的用户,需要大数据支持,一个初级产品是不可能有如此的用户群。于是,我联想到了电影《解忧杂货铺》,这样就可以避开大数据,同时对不法行为也是一种拦截。当然,如果要做成一个成型的产品需要一个漫长的过程。
这样的产品在市面上是存在的,有成功的,也有失败的。当我开始做个项目的时候也并没有要把它做完整,毕竟想法不完整,同时还需要进行一些必要的知识补救。也就是说这只是一个Demo,并不完整的东西,仅仅是为了练习一下技术。最初也想做成一个完整的项目,而且也聚集了一些朋友,不过做到后面有些不尽人意了。大家抱着不挣钱练技术的心态是建设不出好的项目来,而且我觉得主要工作在后端。另外,大家也似乎都很忙,沟通成本也太高了,只好作罢。
所以,在这儿也就不做项目的结构介绍,等做成完整项目之后再做一个全面的输出。毕竟只有一个人弄,还要去学后端,这是又一个漫长的过程。
技术选型
近期主要研究的是vue,之前对比过vue-cli2和vue-cli3的差异,vue-cli3更简洁。但是之前没有研究明白,因此这次选用vue-cli3脚手架来进行研究。为什么研究vue?毕竟是中国人自己搞出来的,必须支持一下。
由于没有UI做图,于是选用一个UI组件库来解决这个难题。相对来说,我个人觉得vux更适合一些,其余的大多是基于商城,组件也并没那么丰富。但是它的缺点就是在某些情况下因为scoped的原因修改内置样式修改不了,于是改用vant。vant应该基于ant-design,设计漂亮,组件易用。
移动端适配之前一直用的rem,rem的适配通常是通过JS动态改变根字体大小来完成,这就需要多一个JS的流程。当然,可以通过css的方式来固定根字体大小,缺点也很明显。淘宝前端emfe团队给了一个相对成熟的适配方式flexible,配合px2rem-loader(px2rem)使用也是相当方便的。关于flexible适配,可以阅读一下《使用Flexible实现手淘H5页面的终端适配》。
我并没使用它们做过实际开发,只是研究的时候发现flexible的适配方式我没搞懂。当viewport缩放动态修改的时候,rem根值也同时动态更改,最后效果和预想的不太一样。于是我只好写死viewport,这样才能恢复我要的效果。可能是我配置的方式没对,以后有空再研究。px2rem我比较喜欢它将特定的样式根据dpr生成适配样式,不过它貌似不能处理行内样式,当然vue极少用行内样式。
另外,emfe在准备更新flexible 2.0版本的时候放弃了更新,改为推荐vw实现适配。rem适配并不完美,可以阅读下大漠老师的文章《再聊移动端页面的适配》。vw是不是就完美呢,也不是,px换成vw会产生像素差。我之前讲过,浮点数始终是不精确的,浮点数还原回px就会发现少了一点。这在移动端还是可以忍受的,关于使用详细可以查阅《如何在Vue项目中使用vw实现移动端适配》。于是,适配我选用vw,感受一下效果。
准备工作
## 构建项目 ##
之前使用的是vue-cli 2,卸掉它,换成vue-cli 3。第一个差别是vue-cli的包名称改为了@vue/cli。如果需要继续使用vue-cli 2的工作方式,需要安装@vue/cli-init包,项目构建命令和vue-cli 2相同。vue-cli其实就是一个模版拷贝的过程,大量的配置会导致模版难以维护,于是重构了vue-cli 3,做了一些初步的封装,开箱即用。你不做任何配置就可以进行开发工作,如果要折腾,可以去修改配置项。
vue-cli 3更换完成,使用vue create命令生成项目,接下来根据需要勾选默认配置。具体的就不啰嗦了,官网文档对配置项做了大致的说明,再不明白可以搜索网上教程。我不太喜欢ESLint这个东西,因为在使用非ES写法的时候就会提示,很烦躁,明明就是正确的JS语法。对比一下,vue-cli 2和vue-cli 3构建的项目,如图:
从结构上看3.x更加简洁,将2.x的build目录、config目录隐藏了起来,改为了使用vue.config.js来完成配置,默认是没有这个文件的,需要自己在项目目录下新建。类似这种配置方式在很多地方都有用到,比如环境变量、测试工具的配置等等。相对于2.x在配置文件内部去做手脚要高明得多,统一管理便于维护。3.x将不需要编译的资源统一放到了public文件夹,包括index.html文件,去掉了2.x的static目录。3.x去掉了router目录,将路由直接放到src下(router.js)。
3.x在src下默认新增了store.js、registerServiceWorker.js两个文件。store.js自不必说,vuex文件,管理vue状态。registerServiceWorker.js说实话,我没有在网上查到太多的资料,大多讲解是针对react的这个文件。vue-cli 3的构建方式是学习了react的脚手架,原理上它们应该是相通的,它的目的是使项目变成一个PWA(Progressive Web Application)。也就是说,注册一个服务来进行缓存,下一次即使没有网络,这个应用依然可以访问。
3.x还多了一个叫做插件的东西,通过vue add命令来添加,在src下会多一个plugins目录。我的理解插件就像被二次封装的模板库,执行添加命令,这个库按照生成器规定的方式被部署到对应的文件中,从而是vue-cli得到扩展。因而vue add并不能取代npm install,具体的介绍可以查看官方文档。只不过,到底有些什么已经可用的插件在官网上看不到,只能通过vue ui在图形界面上查看安装。我是不太喜欢这种傻瓜式的构建方式,特别中二。再加上插件开发者水平参差不齐,不见得符合自己开发的意愿。除了特殊的情况,我更喜欢自己去安装,编写需要的文件。
再来看看,package.json文件,3.x简洁了很多,2.x不少依赖包都不见了。(ps:图中vue3的dependencies中vant是为了展示插件这个目录添加进去的,不是3.x新增内容。)编译运行命令变成了一个名为vue-cli-service的命令,它的底层还是启动一个webpack-dev-server,只不过附带了一些其它功能。换句话说,它其实也是一个插件。如果要更深层次地了解它的工作原理,那么只有去翻源码。此外,2.x中比如browserslist这个字段,在3.x也是存在的,由于我选择配成的文件.browserslistrc。有很多配置文件都可以放入package.json中,个人认为,放在单个文件更加直观更利于维护。
关于vue-cli 3其他相关的介绍,只有移步官网,里面讲解更全面。不得不吐槽,咱啥时候能彻底和IE说拜拜,简直是bull shit,这给前端开发增加了太多的难题!
## 引入UI组件库 ##
前面介绍插件已经引入了vant,引入方式:执行vue ui启动GUI,导入项目。切换到插件 -> 添加插件,选中并安装插件vue-cli-plugin-vant。接下来在plugins目录下就会出现vant.js文件,该文件已将vant引入,而且这个文件也在main.js上引入。vant.js引入有一个Locale变量,我开了代码提示,这时就开始报错了。这并不是什么大问题,但时常会让人莫名其妙。
同样通过GUI图形界面,切换到依赖 -> 安装依赖,切换依赖包的环境,选中并安装vant。
这不是程序员的操作方式,于是我选择命令行安装依赖。
# 通过 npm 安装
npm i vant -S
有四种方式引入组件,第一种:老方法,这似乎是不太美丽的做法。
<!-- 引入样式 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/lib/index.css">
<!-- 引入组件 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/vant.min.js"></script>
<script>
var Vue = window.Vue;
var vant = window.vant;
// 注册 Lazyload 组件
Vue.use(vant.Lazyload);
// 调用函数式组件
vant.Toast('提示');
</script>
第二种:在main.js导入所有组件,当然也可以像插件那样提一个文件出来。
import Vue from 'vue';
import Vant from 'vant';
import 'vant/lib/index.css';
Vue.use(Vant);
第三种:手动按需引入组件。
import Button from 'vant/lib/button';
import 'vant/lib/button/style';
第四种:自动按需引入组件,这才是工程化的做法。
# 安装插件
npm i babel-plugin-import -D
// 在 babel.config.js 中配置
module.exports = {
plugins: [
['import', {
libraryName: 'vant',
libraryDirectory: 'es',
style: true
}, 'vant']
]
};
// 插件会自动将代码转化为按需引入形式
import { Button } from 'vant';
由于我全项目依靠vant,所以,我使用了第二种方式,但这是不科学的,这个下一篇来讲。
## vw适配 ##
前面介绍技术选型已经做了介绍,下面直接操作。
# 安装依赖包
npm i postcss-aspect-ratio-mini postcss-px-to-viewport postcss-write-svg postcss-cssnext postcss-viewport-units cssnano cssnano-preset-advanced postcss-import postcss-url --S
// 配置postcss.config.js
module.exports = {
plugins: {
"postcss-import": {},
"postcss-url": {},
"postcss-aspect-ratio-mini": {},
"postcss-write-svg": {
uft8: false
},
"postcss-cssnext": {},
"postcss-px-to-viewport": {
viewportWidth: 375,
unitPrecision: 3,
viewportUnit: 'vw',
selectorBlackList: ['.ignore', '.hairlines'],
minPixelValue: 1,
mediaQuery: false
},
"postcss-viewport-units": {
"silence": true
},
"cssnano": {
preset: 'advanced',
autoprefixer: false,
"postcss-zindex": false
}
}
}
viewportWidth我配置的375,iphone6设计图,按1倍图处理,因为很多库是使用的1倍图的实际像素来进行适配的。如果不想转换直接使用1倍图像素,可以在selectorBlackList加入'van'来屏蔽转换,'van'是vant库所有样式的前缀。
最后解决vw适配的兼容问题,这个polyfill原理很简单,相当于将vw单位还原为该分辨率的实际像素。
<script src="<%= BASE_URL %>js/viewport-units-buggyfill.min.js"></script>
<script src="<%= BASE_URL %>js/viewport-units-buggyfill.hacks.min.js"></script>
<script>window.onload=function(){window.viewportUnitsBuggyfill.init({hacks:window.viewportUnitsBuggyfillHacks})}</script>
这儿需要注意的是不能使用字体图标,字体图标使用content来完成的,这个polyfill也使用了content。我不解的是postcss-px-to-viewport也使用了,却没有影响。其实,并不建议使用字体图标,字体图标通常包含很大的资源。
最后
这只是技术选型上的配置,配置还并没有完成,比如接口请求封装、打包处理等等。
# 跑下代码
npm run serve