-
v-for 执行在 vue-if 前,同级绑定,在v-for的循环数据为空时,v-if无效,
解决:换不同级绑定 -
props中需要这样赋默认值:{default:true,}否则默认值为空
-
data中直接赋值数据不会响应,要用计算属性或监听属性
-
在DOM渲染前计算结束的表达式的值,(data中的值也是在DOM渲染前结算的),其结果会作为初始值看待,若是给子组件传值,会作为子组件的初始值,不会引起watch的监测执行;另外子组件的props改变,子组件会重新渲染(不会重新创建组件)
-
路由使用了缓存,父组件给子组件传值时,如果父组件传值发生改变,子组件需要监测对应改变的对象值,不然子组件重新渲染还是使用缓存中的值
-
vue渲染template的时间在beforeMount之后,mounted之前,所以渲染template时data值为null,故而报错;但是待后台数据请求成功给data赋值后,p元素能监听到数据的变化,然后更新其innerHTML,所以UI看起来是很正常的
后来经过验证,上述的解决方案是错误的,因为它只针对同步代码有效果。而ajax请求是异步操作,回调函数的执行时间不能确定,所以即使放在created钩子函数中,也不能保证在mounted之前完成数据的请求……
一点小小的感悟,vue生命周期钩子函数的使用并非一成不变的,要根据不同的应用场景而有所改变,稍微总结一下:
beforeCreate:在实例初始化之后,**数据观测(data observer) ** 和 event/watcher事件配置 之前被调用,注意是 之前,此时data、watcher、methods统统滴没有。
这个时候的vue实例还什么都没有,但是$route对象是存在的,可以根据路由信息进行重定向之类的操作。
created:在实例已经创建完成之后被调用。在这一步,实例已完成以下配置:数据观测(data observer) ,属性和方法的运算, watch/event 事件回调。然而,挂载阶段还没开始, e l 属 性 目 前 不 可 见 。 此 时 t h i s . el属性目前不可见。 此时 this. el属性目前不可见。此时this.data 可以访问,watcher、events、methods也出现了,若根据后台接口动态改变data和methods的场景下,可以使用。
beforeMount:在挂载开始之前被调用,相关的 render 函数 首次被调用。但是render正在执行中,此时DOM还是无法操作的。我打印了此时的vue实例对象,相比于created生命周期,此时只是多了一个$el的属性,然而其值为undefined。
使用场景我上文已经提到了,页面渲染时所需要的数据,应尽量在这之前完成赋值。
mounted:在挂载之后被调用。在这一步 创建vm.$el
并替换el,并挂载到实例上。(官方文档中的 “如果root实例挂载了一个文档内元素,当mounted被调用时vm.$el也在文档内” 这句话存疑)
此时元素已经渲染完成了,依赖于DOM的代码就放在这里吧~比如监听DOM事件。
beforeUpdate:$vm.data
更新之后,虚拟DOM重新渲染 和打补丁之前被调用。
你可以在这个钩子中进一步地修改$vm.data,这不会触发附加的重渲染过程。
updated:虚拟DOM重新渲染 和打补丁之后被调用。
当这个钩子被调用时,组件DOM的data已经更新,所以你现在可以执行依赖于DOM的操作。但是不要在此时修改data,否则会继续触发beforeUpdate、updated这两个生命周期,进入死循环!
beforeDestroy:实例被销毁之前调用。在这一步,实例仍然完全可用。
实例要被销毁了,赶在被销毁之前搞点事情吧哈哈~
destroyed:Vue实例销毁后调用。此时,Vue实例指示的所有东西已经解绑定,所有的事件监听器都已经被移除,所有的子实例也已经被销毁。
这时候能做的事情已经不多了,只能加点儿提示toast之类的东西吧。
注:beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed这几个钩子函数,在服务器端渲染期间不被调用。
-
vue 组件watch $route时,首次加载组件时不会监测路由变化,watch 0 和“0”会是不同的,是执行watch
-
vue 前进后退转场动画
<transition :name="transitionName">
<router-view class="router-view" />
</transition>
watch: {
//监听路由
$route(to, from) {
// 前进后退转场动画
const toDepth = (to.path.match(/\/./g) || []).length;
const fromDepth = (from.path.match(/\/./g) || []).length;
const isBack = toDepth < fromDepth;
this.transitionName = isBack ? "slide-right" : "slide-left";
}
}
// 全屏转换动画
.slide-left-enter-active,
.slide-right-enter-active {
transition: all 0.3s ease;
}
.slide-left-leave-active,
.slide-right-leave-active {
transition: all 0.3s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-left-enter,
.slide-right-leave-to {
transform: translateX(100%);
}
.slide-left-leave-to,.slide-right-enter
{
transform: translateX(-100%);
}
/**
* vue 自定义阻止按钮连续点击指令
* 使用 <div @click="search" v-preventReClick="10000">搜索</div>
*/
Vue.directive('preventReClick', {
inserted(el, binding) {
el.addEventListener('click', () => {
el.style.pointerEvents = 'none';
setTimeout(() => {
el.style.pointerEvents = 'auto';
}, binding.value || 2000);
});
}
});