vue-router

router这里踩的坑主要是组件的重用。构建单页面大型应用的话,肯定要开启组件的缓存的,因为一般会要求后退的时候不要重新加载页面,而且要记住原始的滚动位置。
首先,引入router-view的地方要加上keep-alive

<router-view keep-alive></router-view>

然后开启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)

组件中

  <dl v-infinite-scroll="loadMore()" infinite-scroll-disabled="busy" infinite-scroll-distance="7">
<template v-for="item in list">
<dd class="page-item">
</dd>
</template>
</dl>

其中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]')),

VUE常用问题hack修改的更多相关文章

  1. Vue常用性能优化

    Vue常用性能优化 Vue常用的一些优化方式,主要是在构建项目过程需要注意的方面. 编码优化 避免响应所有数据 不要将所有的数据都放到data中,data中的数据都会增加getter和setter,并 ...

  2. 常用CSS HACK

    常用CSS HACK IE6 3像素bug和双边距bug一样的经典 现象: IE6下浮动元素和不浮动元素之间会有3px间隙(3px bug,div.float-left + div.float-non ...

  3. Vue常用经典开源项目汇总参考-海量

    Vue常用经典开源项目汇总参考-海量 Vue是什么? Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的 渐进式框架.与其他重量级框架不同的是,Vue 采用自底向上增量开发的 ...

  4. mysql常用快速查询修改操作

    mysql常用快速查询修改操作 一.查找并修改非innodb引擎为innodb引擎 # 通用操作 mysql> select concat('alter table ',table_schema ...

  5. vue常用

    vue常用的路由的状态管理

  6. 五、vue常用UI组件

    下面简单的总结下vue常用的一些UI 组件,有一些我也没怎么用过,这里先罗列出来,便于自己后面使用的时候查找方便,大家有更好的可以给我推荐哦~ vuex: vux github ui demo:htt ...

  7. (二)Vue常用7个属性

    学习vue我们必须之到它的7个属性,8个 方法,以及7个指令.787原则 el属性 用来指示vue编译器从什么地方开始解析 vue的语法,可以说是一个占位符. data属性 用来组织从view中抽象出 ...

  8. Vue常用语法及命令

    1,Vue常用语法 vue常用语法之变量的定义 // 1,变量相关 // 变量的提升 var username = "雪雪"; var username ; console.log ...

  9. Vue常用的GitHub项目

    Vue常用的GitHub项目(Demo案例) 应用实例 https://github.com/pagekit/pa... pagekit-轻量级的CMS建站系统 https://github.com/ ...

随机推荐

  1. Flutter 容器Container类和布局Layout类

    1.布局和容器 [布局]是把[容器]按照不同的方式排列起来. Scaffold包含的主要部门:appBar,body,bottomNavigator 其中body可以是一个布局组件,也可以是一个容器组 ...

  2. 不安装证书如何通过模拟器+Fiddler抓包APP的HTTPS请求?

    模拟器抓取https方法 说明:为了解决安卓手线上不能抓取https请求,以下整理通过模拟器抓取https请求方法如下:前置条件:安卓模拟器:夜神抓包工具:Fiddler汉化中文升级版1无需FIDDL ...

  3. day33:进程II

    目录 1.锁:Lock 2.信号量:Semaphone 3.事件:Event 4.进程队列:Queue 5.生产者和消费者模型 6.JoinableQueue 锁:Lock 1.锁的基本概念 上锁和解 ...

  4. Wireshark中遇到的epoch time

    使用Wireshark分析DNS时遇到的Epoch time 首先看一下Wireshark分析DNS的情况(如下图): 这是协议树的第一项,第一项中的第五行出现了Epoch Time,查阅资料之后才知 ...

  5. Macbook pro 下修改MySQL数据库密码

    步骤: 1. 打开终端 Terminal, 找到Mysql 的安装路径,一般默认安装路径为:/usr/local/mysql-5.7.12-osx10.11-x86_64/bin [注:我安装的Mys ...

  6. JavaScript学习系列博客_1_JavaScript简介

    这个系列博客主要用来记录本人学习JavaScript的笔记,从0开始,即使有些知识我也是知道的.但是会经常忘记,干脆就写成博客,没事的时候翻来看一看,留下一点学习的痕迹也好.可能写博客的水平暂时不太好 ...

  7. Micro LED巨量转移技术研究进展

    近年来,Micro LED因其功耗低.响应快.寿命长.光效率高等特点,被视为继LCD.OLED之后的新一代显示面板技术.Micro LED的英文全名是Micro Light Emitting Diod ...

  8. Mybatis分页插件: pageHelper的使用及其原理解析

    在实际工作中,很进行列表查询的场景,我们往往都需要做两个步骤:1. 查询所需页数对应数据:2. 统计符合条件的数据总数:而这,又会导致我们必然至少要写2个sql进行操作.这无形中增加了我们的工作量,另 ...

  9. 四则运算生成命令行程序 (Python)

    Github项目地址:Github Pages 结对项目成员:张鹏 3118004985 郑靓 3118004988 一.项目需求分析 二.功能实现 三.代码实现or功能说明 ★ GUI功能扩展说明 ...

  10. Hop: Heterogeneity-aware Decentralized Training

    郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! 以下是对本文关键部分的摘抄翻译,详情请参见原文. ASPLOS 2019 Abstract 最近的研究表明,在机器学习的背景下,去中心化算 ...