学习使用Vue2.0于移动端开发
偶然在GitHub论坛看到一个“基于Vue2.0高仿微信App”,点入一看,效果果真非常逼真。于是,立马入手学习。也记录对一些地方的理解:1.过滤器该项目中用到了时间过滤器,能将时间戳以固定的格式打印输出。过滤器官方文档在此,正如文档中所给出定义过滤器的两种方法,分为全局和局部,用在两个地方双括号插值和v-bind表达式,且过滤器应该添置在js表达式的尾部,由“管道”即“|”指示。该项目中
偶然在GitHub论坛看到一个“基于Vue2.0高仿微信App”,点入一看,效果果真非常逼真。于是,立马入手学习。也记录对一些地方的理解:
1.过滤器
该项目中用到了时间过滤器,能将时间戳以固定的格式打印输出。过滤器官方文档在此,正如文档中所给出定义过滤器的两种方法,分为全局和局部,用在两个地方双括号插值和v-bind表达式,且过滤器应该添置在js表达式的尾部,由“管道”即“|”指示。该项目中时间过滤器的定义是全局形式,且单独放置在名为filters的文件夹下,由main.js中引入,进而全局注册使用。
filters/index.js 详细代码:
const filters = {
/**
* 功能:将时间戳按照给定的 时间/日期 格式进行处理
* @param {Number} date 时间戳
* @param {String} fmtExp 时间格式 'hh:ss'
* @returns {String} 规范后的 时间/日期 字符串
*/
fmtDate: function(date, fmtExp) {
var date = new Date(date)
var o = {
"M+": date.getMonth() + 1, //月份
"d+": date.getDate(), //日
"h+": date.getHours(), //小时
"m+": date.getMinutes(), //分
"s+": date.getSeconds(), //秒
"q+": Math.floor((date.getMonth() + 3) / 3), //季度
"S": date.getMilliseconds() //毫秒
};
//此处的匹配项是如果日期中需要输出年,对年份的处理!
if (/(y+)/.test(fmtExp))
fmtExp = fmtExp.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
//后面就是截取时间的处理,将h+和s+即小时和分钟数截取出来
for (var k in o)
if (new RegExp("(" + k + ")").test(fmtExp))
fmtExp = fmtExp.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmtExp;
}
}
export default (Vue) => {
Object.keys(filters).forEach(key => {
Vue.filter(key, filters[key])
})
}
最后的导出部分改写为常规的函数写法:
export default function(vue){
//Object.keys()方法返回对象的可枚举属性和方法,因为可能会有多个过滤器
//对每一个过滤器都进行全局定义,参见文档中全局的方法
return Object.keys(filters).forEach(
function(key){
return vue.filter(key,filters[key])
}
);
}
再写详细一点,以免日后自己回过头半天不能领悟。上面最后的意思,首先Object.keys( )方法将当前的filters对象中的或者属性以key-value的数组形式返回,这里即是fmtDate( )返回。接着对数组中的每一项,以key为关键,返回过滤器的定义,即vue.filter(key,function),这里就是返回
vue.filter(fmtDate,function(date, fmtExp) {
var date = new Date(date)
var o = {
"M+": date.getMonth() + 1, //月份
"d+": date.getDate(), //日
"h+": date.getHours(), //小时
"m+": date.getMinutes(), //分
"s+": date.getSeconds(), //秒
"q+": Math.floor((date.getMonth() + 3) / 3), //季度
"S": date.getMilliseconds() //毫秒
};
……
})
然后在main.js中引入注册。(PS:不过这里的写法有点点不清楚。)
import filters from './filters' //将全部过滤器放在 filters/index.js 中便于管理
// 注册全局过滤器
filters(Vue)
2.正则表达式
也是上面的时间格式化中对时和分的提取,最初看时一头雾水,结果!理解了意思之后,发现自己好笨。自己的难点是上面代码中的replace( )参数是RegExp.
1,参数是哪里来的(笑哭)网上解释说“
1
,
参
数
是
哪
里
来
的
(
笑
哭
)
网
上
解
释
说
“
1是匹配到的正则表达式的第一个字表达式”,而且一直在纠结第一个if里的内容,打印也不输出。事实证明调试是非常有用,于是单步调试。
正如上图所示if里的y+,最初因为项目中没有输出年份,格式化为hh:ss,因此if始终不执行。在理解了下面对小时分钟的处理后,再格式化前面加上年 yyyy:hh:ss,果然如所料,这时候就匹配到了fmtExp的字符串yyyy,也就能对时间戳的年给取出来。
同理,上面的第一次h+,匹配到了hh,于是对时间戳进行处理。分两位还是一位,如1或者11,如果只有一位时,返回值就直接是1(h);如果两位,首先处理为“0011”,接着对“0011”取“11”的字符串长度即2个,也就是11(h)。
第二次s+,返回就为分钟数。
通过上面类似的处理就能将时间戳格式化为我们想要的格式。
3.自定义指令
对消息的滑动处理进行了自定义指令实现,自定义指令文档在此,同样也分为全局和局部两种。在定义指令时一般有好些钩子函数:bind、inserted、update等,且会该钩子函数会被传入以下参数,el、binding、name……详细参见文档。
???????疑问:关于文档中后面的例子,参数‘vnode keys’不知道是如何获取的。
本项目里的自定义指令,代码如下:
directives: {
swiper: {
bind: function(element, binding) {
var isTouchMove, startTx, startTy
//addEventListener(event,function,useCapture)用于向指定元素添加事件句,
// 相应的有removeEventLisener移除所添加的
// 第三个参数指定事件在捕获或者冒泡阶段的执行(前者为true,后者false)
element.addEventListener('touchstart', function(e) {
var touches = e.touches[0]
startTx = touches.clientX
startTy = touches.clientY
isTouchMove = false;
}, false);
element.addEventListener('touchmove', function(e) {
var touches = e.changedTouches[0],
endTx = touches.clientX,
endTy = touches.clientY,
distanceX = startTx - endTx,
distanceY = startTy - endTy;
if (distanceX < 0) { //右滑
if (Math.abs(distanceX) >= Math.abs(distanceY)) {
if (Math.abs(distanceX) > 20) {
element.style.transition = "0.3s"
element.style.marginLeft = 0 + "px"
}
}
} else { //左滑
if (Math.abs(distanceX) >= Math.abs(distanceY)) {
if (distanceX < 156 && distanceX > 20) {
e.preventDefault()
element.style.transition = "0s"
element.style.marginLeft = -distanceX + "px"
isTouchMove = true
}
}
}
// e.preventDefault()
}, false);
element.addEventListener('touchend', function(e) {
if (!isTouchMove) {
return;
}
var touches = e.changedTouches[0],
endTx = touches.clientX,
endTy = touches.clientY,
distanceX = startTx - endTx,
distanceY = startTy - endTy,
isSwipe = false
if (Math.abs(distanceX) >= Math.abs(distanceY)) {
if (distanceX < 0) {
return;
}
if (Math.abs(distanceX) < 60) {
isSwipe = true
element.style.transition = "0.3s"
element.style.marginLeft = 0 + "px"
} else {
element.style.transition = "0.3s"
element.style.marginLeft = "-156px"
}
}
}, false);
}
}
}
在上面的自定义指令的实现中,对绑定元素的dom操作用到了addEventListener( )方法,相应的还有移除该方法添加的事件句柄的方法removeEventListener(event,function(){},useCapture )。其中三个参数中,第一个是时间名称,第三个则是布尔值用于指定时间在捕获或者冒泡阶段执行。
<!DOCTYPE html>
<html>
<head>
<title>测试事件冒泡捕获阶段</title>
</head>
<body>
<div class="a">
<li class="b">
<a href="#" class="c">buhuo</a>
</li>
</div>
</body>
<script type="text/javascript">
var div = document.getElementsByClassName('a')[0];
var li = document.getElementsByClassName('b')[0];
var a = document.getElementsByClassName('c')[0];
//对事件冒泡过程添加函数处理,默认是false
div.addEventListener('click',function(event){
console.log('div');
});
li.addEventListener('click',function(event){
console.log('li');
});
a.addEventListener('click',function(event){
console.log('a');
})
//对事件捕获过程处理,第三个参数设为true
div.addEventListener('click',function(event){
console.log('div');
},true);
li.addEventListener('click',function(event){
console.log('li');
},true);
a.addEventListener('click',function(event){
console.log('a');
},true)
</script>
</html>
下面则是验证的效果:
再使用event.stopPropagation()方法——终止事件在传播过程的捕获、目标处理或起泡阶段进一步传播。在捕获事件方法中,div标签的监听事件中调用该方法,明显的只有div输出。
这里为什么div还会输出呢?因为所谓的捕获与冒泡并不是相对本元素而是腹肌或者子级的元素,因此冒泡也是不会冒泡到兄弟元素的!
将stopPropagation()方法下移到li标签:
将stopPropagation()方法下移到a标签时,输出了两个a是因为一个是捕获阶段捕获的,下面的那个则是冒泡阶段,但又由于调用了stopProgagation方法,冒泡事件被终止于a标签。
关于事件的捕获阶段和冒泡阶段的划分详见下面的图,参考自网上,不过出处一时找不到了,暂且自己画一下。
!!!关于这部分内容,先记着一条有用的总结,若想要捕获事件就要在目标元素事件发生之前,也就是捕获阶段。
不过对其中的很多地方尚且不清楚(后补!)。
4.router-link中的一系列标签to、tag、exact
(1)tag标签:
//原未改时
<router-link to="/foo" >foo</router-link>
<!-- 渲染结果 -->
<a href="/foo">foo</a>
//修改后
<router-link to="/foo" tag="li">foo</router-link>
<!-- 渲染结果 -->
<li>foo</li>
(2)exact标签
原文档中解释:路由的激活在exact匹配模式下,会严格按照给出的路径,只有完全匹配时才激活该路径!官方效果实例
“/” :第一个“/”无论是点击后面哪个li标签均会被激活,因为无论哪个路径都包含”/”;
而第二个”/”只会在完全匹配,也就是仅仅在点击前两个li标签时会被激活;
同理,后面的user系列也一样,第一个/users的li标签只要在后面的users系列被点击即被激活。而包含了exact的仅仅前两个/users被激活;
类似的其他的渲染类似!
更多推荐
所有评论(0)