简介
这是一个功能比较简单的网站:
- 做测试题目
- 计算展示测试结果
- 生成证书
- 分享结果
- 查看每种类型的详细介绍
- 外链到各个不同的设计学院和 open house
痛点
第一次自己 handle 一整个项目
第一次根据自己根据需求去配置 webpack
第一次用 vue 做一个功能非常完整闭环的项目
移动端适配
克服
如何自己 handle 好一个项目呢?
其实在开发中,单人开发除了在开发时长、任务量和周期上不沾上风以外,根本不会存在代码冲突、配合不好之类的问题
并且在多人开发中,组件如何抽离、怎么抽都需要提前商量好,当然单人开发不需要商量,但是还是要自己提前计划好
还有一个很重点的事情就是在开始写代码之前,一定要认真过每一个设计稿。然后把设计稿串联起来消化需求之后,对项目该如何架构有明确想法了再开始写代码。
最后还有一个很重要的点。在我的观察范围内,感觉做开发的其实普遍都存在一些主观的意愿在项目了,经常做到某些部分设计给的不清晰, pm 的需求也不是特别清晰的时候我们会按照我们想的来做,这没问题,问题在于后面他们提出了要求之后,我们经常和他们 argue 目的只是为了不改代码,但通过这个项目,我意识到一个问题。 有时候 pm 和设计的坚持其实是为了用户体验和交付的东西更好。 而我们因为偷懒不想改掉的东西可能让我们这一次的项目就并没有想想中的更完美。也可能我就是想做到别人用我做的东西的时候,也有我看见设计师设计的稿子的时候那样的惊叹。所以很多东西都不能似是而非,应该严守底线。
关于这个项目 webpack 的配置
因为我们的项目打包好交给后端的时候,需要按照后端想要的文件配置,所以使用生产环境的 webapck
配置的时候,我们就理清楚,输出出来的文件包一定是这个格式:
- images - 图片文件
- fonts - 字体文件
- entry - main.js 文件
- pags - main.html 文件
webpack.prod 输出配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| output: { path: path.resolve(__dirname, "prod"), filename: "entries/main.js", chunkFilename: "entries/[name].[hash].js" }, plugins: [ new HtmlWebpackPlugin({ template: "./src/index.html", filename: "./pages/main.html" }) ], module: { rules: [ { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'file-loader', options: { limit: 10000, name: '[name].[ext]', outputPath: 'images', }, }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'file-loader', options: { limit: 10000, name: '[name].[ext]', outputPath: 'fonts', }, }, ], }
|
遇到的坑
在我配置好各个环境下的 webpack 之后,我的执行 npm run start-local
成功的起了起来,但是页面没东西!!!第一反应是 vue-loader 没有生效, 但是查看 vue-loader 的配置是正确的没错
1 2 3 4 5
| { test: /\.vue$/, include: [path.resolve(__dirname, 'src/')], use: 'vue-loader', }
|
后来去各种 Google、 百度才发现还需要在 resolve
里加上 extensions
1 2 3 4 5 6 7
| resolve: { alias: { '@': path.resolve(__dirname, 'src'), '*': path.resolve(__dirname, 'src/assets'), }, extensions: ['*', '.js', '.vue', '.json'], }
|
是因为各种解析工具默认只能识别 `js` 文件,所以你必须在 `extensions` 加上 vue 的后缀名,以便他去解析你的 vue 文件。
在 history 模式下, 打包出来的文件,如果你直接本地打开,是空白的,在根元素内没有内容。为此我纠结了很久一度认为 vue-router 是不是有什么问题。最后怎么解决的呢?
后来把打包的文件放到服务器上之后,路径指定到了该文件夹下的 `index.html` 这时就能找到对应的资源,页面可以正常显示了。
在 history 模式下, 我传入了 route 表,定义的一些路由相关的东西,但是在访问的时候并不生效。访问的页面是404
1 2 3 4 5 6 7 8 9 10 11
| const router = new VueRouter({ mode: "history", base: __dirname, routes });
new Vue({ el: "#root", render: h => h(App), router });
|
经过各种google、百度,才知道,在 history 模式下用 webpack dev server 需要配置一个Fallback
1 2 3 4 5 6
| devServer: { contentBase: path.resolve(__dirname, "local"), port: 8001, hot: true, historyApiFallback: true }
|
如webpack官网给出的解释:
神奇传送门 - webpack
初次兼容移动端开发,在 IOS 里踩了一个巨大的坑。有三个页面,设计师要求必须一个屏幕显示完,不允许滚动…这种需求放安卓端很好搞定的,毕竟安卓机的宽高都挺大的,主要是可以控制成全屏显示。内容都可以放下且放在一个屏幕内。但是! 苹果就不是了,他是开发最痛苦的存在吧,也许…
起初在 chrome 的模拟器上,各种调试都是完美的,但是一到真机上的浏览器就乱的妈都不认识…这是时候什么 vh
什么 clientHeight
都是虚的。这个时候只能使用 innerHeight
去获取到当前视图的真实高度。经过大神指点:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <script> (function(listener){ document.addEventListener('resize',listener, false) document.addEventListener('orientationchange',listener, false) })(function(){ if(document.documentElement.style.setProperty){ document.documentElement.style.setProperty( '--vh', window.innerHeight / 100 + 'px' ) } }) </script>
|
- 在 style 文件里使用该自定义属性(第一行height是兜底的,为的就是如果不能识别自定义属性的情况,提高兼容性)
1 2
| height: calc(~'100vh - 60px'); height: calc(var(--vh, 1vh) * 100 - 60px);
|
一开始以为就这样就可以快快乐乐的交付,实际呢? 在 UAT 的时候因为首页面是固定的一个页面展示所有内容,就那点高度,那点宽度,根本不可能,样式丑的可怜。本来以为这样修改之后就万事大吉了,看来还是那句老话,你不能限制用户在前段的想象力。出现问题的地方就是用户的屏幕可能并没有锁定竖屏显示,所以使用网站的时候,他可能把屏幕横过来了。这时,你的 innerHeight
对应的就变了,一个屏幕现显示所有内容,在竖屏的case下,显然不可能。还出现了一个关键的问题 — innerHeight
的值改变是会滞后的。这很严重,在 safari 上好像没有什么影响,但是到了 IOS 的 chrome 上,就发现了再转为竖屏的时候高度不对。如何是好呢?因为本项目是单页应用,所以 app.vue 文件的生命周期不管页面如何跳转都存在。所以我把上面计算 --vh
的逻辑放入了 app.vue 的 mounted
生命周期。然后在 updated
的时候,再去获取一下当前的 innerHeight
的值,这样保证了每个页面试图的高度是正常的,不会受到 safari 是否有工具栏或者地址栏而影响。这里最大的心得就是充分利用好生命周期!!!
IOS 橡皮筋
我想应该有很多开发同学和我一样有被 IOS Safari 的橡皮筋效果恶心到吧~~~
在这个项目的做题页面,因为 UI 出于样式考虑,想要一个屏幕显示完整不允许滚动和首页类似,而橡皮筋效果才不管你那么多呢,只要你拉他就一定能给你抬一个高度出来,甚烦!!!
于是我在这个页面写下了这样的代码:
1 2 3 4 5 6 7 8
| document.body.scrollTop = 0; document.body.addEventListener('touchmove', bodyScroll, { passive: false, });
function bodyScroll(event) { event.preventDefault(); },
|
确实管用了不少,这个页面没有橡皮筋效果了,你以为完美了吗?太天真了!!!!
随着测试的深入,发现只要前一个页面用了橡皮筋效果,最后到这个页面依旧保持,只要你不手动把橡皮筋还原,真TM恶心,我真是口吐芬芳。所以归纳一下现在的问题就是:
首页要禁止掉橡皮筋效果
禁止的同时不能影响它局部可以滚动的要求
这个是真难!我真的前前后后搞了很久,如果像上面代码那样禁止掉默认行为肯定不行,局部无法滚动,最后的最后,终于让我熬出来了。Talk is cheap, show me the code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| mounted() { this.width = window.innerWidth
if (this.width < 1024) { document.body.style.position = 'fixed'; document.body.style.top = 0; document.body.style.left = 0; document.body.style.width = '100%'; document.body.style.height = '100%'; } }, beforeDestroy() { if (this.width < 1024) { document.body.style.position = 'inherit'; } },
|
只需要把 body
的 position 设置为 fixed
并且在销毁这个组件的时候还原 position
的值就可以了。