摘要:欢迎体验提墨瞳漫画这里踩的坑主要是组件的重用。这样可以防止图和图片大小不一样引起的页面跳动继而导致的加载图片时机错误。跨域时,会先发送一个空的请求来查看接口是不是支持跨域,再发送一次真实请求。
前言
博主也是vuejs萌新,公司仅我一个前端,收到做h5的需求后,马上想到要用下vuejs,于是说服领导,开始慢慢钻研,现在记录一下踩到的坑。这些坑主要是在一些组件的使用上,其它的只要好好看官方文档就好了,vue,vue-router, vuex的文档相当重要。
欢迎体验提bug 墨瞳漫画 m.cm233.com
vue-routerrouter这里踩的坑主要是组件的重用。构建单页面大型应用的话,肯定要开启组件的缓存的,因为一般会要求后退的时候不要重新加载页面,而且要记住原始的滚动位置。
首先,引入router-view的地方要加上keep-alive
然后开启html5 history模式,并开启位置纪录
const router = new Router({ history: true, // use history=false when testing saveScrollPosition: true })
开启keep-alive以后,当要求一个组件的内容发生变化时,比如 漫画详情页面是一个路由带参数的组件,当参数变化时,router会重用这个组件,而不是重新请求数据,这显然是不符合要求的,所以正确的姿势是:
首先,用一个字段保存这个路由参数,
用router的钩子函数data获取路由变化参数,保存到字段里
route:{ data: function(transition){ this.bookId = transition.to.params.id; } }
写一个watcher来拉取数据并填充模版,因为在data钩子函数中,我们已经修改了相应字段,所以当路由参数更改时会直接触发这个watcher
watch: { "bookId" : function(val){ //do something } }
如果是多个参数的,可以把这些参数放到一个对象里,watcher采用深监测
route:{ data: function(transition){ this.watcher.type = transition.to.params.type; this.watcher.id = transition.to.query.id; } }, watch : { "watcher" : { handler: function(val){ //do something window.scrollTo(0,0);// 不使用缓存时,不使用记录好的用户位置,滑倒顶部 }, deep: true } }
一开始没有用这种方法出了很多的bug,改了以后,路由和缓存方面的逻辑瞬间就变得清晰了,组件的切换也更加流畅了。
第二个坑就是关于缓存页面浏览位置的纪录,router是通过html5 history的pushState来纪录当前滚动位置的,切换路由的时候,把当前位置push进去,用户后退时,会触发onpopstate事件,这个时候再把位置取出来并滚动到指定位置,但是!某些浏览器本身也设置了一些奇怪的位置滚动,vue-router的滚动就失效了,所以需要延迟执行一下
window.addEventListener("popstate",function(e){ setTimeout(()=>{ window.scrollTo(0,e.state.pos.y);//通过打log,发现了位置纪录在这个变量里了 },300) },false);
然而,浏览器只能记录一个位置,所以会有这样的情况: 从m.cm233.com 到 m.cm233.com/book,再返回到m.cm233.com,这时浏览器跳到了当时记录的位置,但是再前进到/book时,浏览器还是会停在首页的那个位置上,这个bug暂时还没有解决,好在用户场景不是很多。所以告诉我们,子页面路由参数变化的时候,要把滚动条人工弄到最上面,要不然就会滚动到入口页面的浏览位置。也就是watcher里还要加一句如上的滚动。
页面标题也是要手动更改的,所以每个页面要放一个专门的title变量存一下,然后在data钩子函数(用于组件缓存时) 和 路由参数的watcher(用于组件更新时) 里 都改变title
route:{ data: function(transition){ this.title = "hiahia"; document.title = this.title; } }, watch : { "id" : function(val){ this.title = "hiahia"; document.title = this.title; } }
通常页面的标题不是固定的,用变量存储title,主要是为了记住上一次组件被用的时候的title,以便于重用的时候更换。
然而,ios微信不会监测document.title的变化,所以要写一个专门针对它的hack,通过创建iframe
//全局函数 window.isWeiXin = function(){ var ua = window.navigator.userAgent.toLowerCase(); if(ua.match(/MicroMessenger/i) == "micromessenger"){ return true; }else{ return false; } } window.weiXinChange = function(title){ if(window.isWeiXin()){ document.title = title; var iframe = document.createElement("iframe"); iframe.src = "./favicon.ico"; iframe.style.display = "none"; iframe.onload = function(){ setTimeout(function() { document.body.removeChild(iframe); }, 0); } document.body.appendChild(iframe); } } //组件中 route:{ data: function(transition){ this.title = "墨瞳漫画"; document.title = this.title; window.weiXinChange(this.title); } }, watch : { "id" : function(val){ this.title = "墨瞳漫画"; document.title = this.title; window.weiXinChange(this.title); } }vue-infinite-scroll (directive)
(为什么不自己写!)
组件地址 https://github.com/ElemeFE/vue-infinite-scroll 饿了么出品
使用方法
main.js
import Scroll from "vue-infinite-scroll" Vue.use(Scroll)
组件中
其中busy这个变量比较重要,他控制着这个指令是否继续执行,当没有下一页数据的时候,应该把busy置为true来关闭滚动加载。正在读取下一页数据时,要先把busy置为true,数据返回时在置为false
loadmore(){ this.busy = true; someApi.someFunction().then((data) => {this.busy = false;}) }
但是这个组件在路由切换的时候会出问题,routerView被移除时,组件会触发加载(大概是因为页面高度突然塌陷),而且会一直加载到我们自己设置的停止条件(busy=true)。所以离开页面的时候,需要在路由的deactivate钩子函数里把滚动关掉,再次进入页面的时候再开启(路由无变化在data钩子函数里开启,有变化的话在watcher里开启,如果不需要在路由改变时向子组件延时传递参数也可以都在data钩子函数里开启)
route:{ deactivate: function(transition){ this.busy = true; transition.next(); }, data: function(transition){ if(){ this.busy = false; }//这里输入组件路由参数没有变化的条件 } }lazyload
(为什么不自己写!)
网上找了几个lazyload的组件,都不太好使,就自己改了一个,是改了一个,原组件叫vue-lazyload, 毛病还挺多的,写这个组件的人估计没有真正在大项目中用过就匆匆发布在npm了,es6版本也写的不伦不类的 - -,不过还是很厉害,自己写的话毛病肯定会更多。我改后的放在https://github.com/Ganother/blog/blob/master/lazyload.js了,是个较为稳定的版本。其中过渡动画写在img-loaded这个class里
/*简单的透明度渐入,图片加载完成后会删掉这个class,以防router切换缓存页面时再次引起动画*/ .img-loaded { animation: loaded .2s ease-in-out; } @keyframes loaded { 0%{ opacity: 0; } 100%{ opacity: 1; } }
let loadingJpg = require("assets/loading.jpg");//这里引入一张loading图,会被转成base64 Vue.use(VueLazyload, { preLoad: 1.3, //图片顶端距窗口顶端1.3个屏幕高度时开始加载 loading: loadingJpg, error: loadingJpg })
自适应的图片:如果服务端传过来的图片带了宽高信息,可以在img外层包一个class为img-bar的元素,图片过来的时候先设置一个min-height为响应高,组件在图片加载后会自动取掉这个min-height。这样可以防止loading图和图片大小不一样引起的页面跳动继而导致的加载图片时机错误。
vue-resource跨域时,会先发送一个空的options请求来查看接口是不是支持跨域,再发送一次真实请求。还不是很了解这种方式的好处,当接口较多时,请求数量多了一倍也是有点尴尬的,所以要设置一下。而且如果接口每次都打印空参数的log的话。。。嗯。
Vue.http.options.emulateJSON = true; Vue.http.options.headers={ "Content-Type":"application/x-www-form-urlencoded; charset=UTF-8" };结构目录
vue-cli直接构建的,src里的目录如下
api 放一些ajax请求接口的函数
assets 放一些静态资源,图片,公共sass
directives 放一些指令js,比如改动后的lazyload
pages 页面入口组件,用在router中
components 小组件们
vuex vuex
app.vue
main.js
另外,可以修改下生成的静态文件,vue-cli默认声称的静态文件时间戳是加在文件名上的,如app.fefdfd7s8f78sd7.js,这样版本迭代很快后会使服务器上积压过多无用文件,我们希望这样加时间戳 app.js?t=32j32ih4u32h 所以改一下webpack.prod.conf.js就好了,如下
output: { path: config.build.assetsRoot, filename: utils.assetsPath("js/[name].js?t=[chunkhash]"), chunkFilename: utils.assetsPath("js/[id].js") } new ExtractTextPlugin(utils.assetsPath("css/[name].css?t=[contenthash]")),
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/80434.html
摘要:自适应四宫格有这样一张设计稿,左右两边白色间距为,中间间距为,每一行的两张图是等宽的即平分去掉间距后的宽度有一种方法是和设计师商量,把所有的具体尺寸改为百分比尺寸。。 自适应四宫格 有这样一张设计稿,左右两边白色间距为4px,中间间距为10px,每一行的两张图是等宽的(即平分去掉间距后的宽度) showImg(http://www.ganother.com/images/four-it...
摘要:自适应四宫格有这样一张设计稿,左右两边白色间距为,中间间距为,每一行的两张图是等宽的即平分去掉间距后的宽度有一种方法是和设计师商量,把所有的具体尺寸改为百分比尺寸。。 自适应四宫格 有这样一张设计稿,左右两边白色间距为4px,中间间距为10px,每一行的两张图是等宽的(即平分去掉间距后的宽度) showImg(http://www.ganother.com/images/four-it...
摘要:不过实践中发现淘宝开源的可伸缩布局方案效果更好且更容易使用。淘宝的方案总结为根据设备设备像素比设置的值,保持视口始终等于设备物理像素,接着根据屏幕大小动态计算根字体大小,具体是将屏幕划分为等分,每份为,就等于。 最近参与了APP内嵌H5页面的开发,这次使用vuejs替代了jQuery,仅仅把vuejs当做一个库来使用,效率提高之外代码可读性更强,在此分享一下自己的一些开发中总结的经验。...
阅读 1287·2021-11-24 09:39
阅读 2630·2021-09-30 09:47
阅读 1324·2021-09-22 15:15
阅读 2410·2021-09-10 10:51
阅读 1953·2019-08-30 15:55
阅读 2976·2019-08-30 11:06
阅读 894·2019-08-30 10:53
阅读 829·2019-08-29 17:26