记录Vue2常见问题
props $emitprovide/inject 或者 element-ui的广播broadcast/dispatchEventEmmitter机制, 在复杂一些可以用tapablejsVue.$prototype.$bus = new Vue();
this.$bus.on() // 监听
this.$bus.emit() // 触发
$refs、$parent、$children、$attrs、$listeners 也算 不推荐,存在耦合Vuex当 <style> 标签有 scoped 属性时,它的 CSS 只作用于当前组件中的元素。
其原理是通过使用 PostCSS 来实现以下转换:
html<template>
<div class="red" data-v-f3f3eg9>hi</div>
</template>
<style>
.red[data-v-f3f3eg9] { color: red; }
</style>
>>>/deep/ or ::v-deepDOM 和 diff 算法使我们的应用拥有最佳的性能表现。追求高效的过程还在继续,vue3中引入Proxy对数据响应式改进以及编译器中对于静态内容编译的改进都会让vue更加高效。computed 参数可以是函数或对象,如果是函数转换为对象的存值器,返回一个值watch 参数可以是函数或对象,函数会转换为对象{immediate: false, deep: false}beforeEach (to,from,next) 常用于登录权限相关验证
next:路由控制参数next():如果一切正常,则调用这个方法进入下一个钩子next(false):取消导航(即路由不发生改变)next('/login'):当前导航被中断,然后进行一个新的导航next(error):如果一个Error实例,则导航会被终止且该错误会被传递给router.onError()afterEach(to,from) 路由改变后的钩子beforeEnter(to, from, next)this ,如果想使用this则在next方法回调里使用beforeRouteUpdate (to,from,next)beforeRouteLeave (to,from,next)strict: true 直接修改state会控制台报红plugin: [myPlugin]tsexport default store => {
// 初始化时从localStorage获取数据
if(localStorage) {
const user = JSON.parse(localStorage.getItem('user'))
if (user) {
store.commit('user/login')
store.commit('user/setUsername', user.username)
}
}
// 用户状态发生变化时缓存之
store.subscribe((mutation, state) => {
if (mutation.type.startsWith('user/')) {
localStorage.setItem('user', JSON.stringify(state.user))
} else if (mutation.type === 'user/logout') {
localStorage.removeItem('user')
}
})
}
key的作用主要是为了高效的更新VDOM,其原理是vue在patch过程中通过key可以精准判断两 个节点是否是同一个,从而避免频繁更新不同元素,使得整个patch过程更加高效,减少DOM操作量,提高性能。key可能引发一些隐蔽的bug 如列表更新或相同标签名元素的过渡切换new Vue(el:'#app') 只能指定一个入口template下的元素div。其实就是"树"状数据结构中的"根"。diff算法要求的jsexport default {
data() => ({
list: []
}),
async created() {
const list = axios.get('/api/list');
this.list = Object.freeze(list);
}
}
如果是大数据长列表,可采用虚拟滚动,只渲染少部分区域的内容
参考vue-virtual-scroller、vue-virtual-scroll-list
html<recycle-scroller
class="items"
:items="items"
:item-size="24"
>
<template v-slot="{ item }">
<FetchItemView
:item="item"
@vote="voteItem(item)"
/>
</template>
</recycle-scroller>
functionalhtml<template functional>
<div class="cell">
<section v-else class="off"></section>
</div>
</template>
<script>
export default {
// 无状态组件不能有props和data
// props: ['value']
}
</script>
html<template>
<div>
<ChildComp/>
</div>
</template>
<script>
export default {
components: {
ChildComp: {
methods: {
heavy () { /* 耗时任务 */ }
},
render (h) {
return h('div', this.heavy())
}
}
}
}
</script>
keyv-show与v-ifkeep-alive合理使用computed替代method 或 watchis动态组件递归与不同组件使用无异,唯一要注意的是递归首要考虑终止条件,那递归组件必须与v-if配合使用
| 父组件中定义 | 子组件中使用 | |
|---|---|---|
| 默认插槽 | <template v-slot>可简写 <my-comp v-slot> | <slot> |
| 具名插槽 | v-slot:header | <slot name='footer'/> |
| 作用域插槽 | v-slot:default="slotProps" | <slot v-bind:user='user'>{{user.name}}</slot> |
<slot>后备内容</slot>我们认为Vue和WebComponents是互补的技术。可以把自定义元素继承到Vue应用中,也可以使用Vue来构建和分发自定义元素。
自定义元素和Vue组件的相同点
但是Vue组件显然更强大一下
jscomponents: {
'async-com': () => ({
component: new Promise(resolve => {
setTimeout(() => {
resolve(import('./components/AsyncComp.vue'))
}, 2000)
}),
loading: LoadingComp,
error: ErrorComponent,
// error: {render: () => h('div', 'error')}
timeout: 3000,
delay: 200,
timeout: 3000
})
}
jsVue.config.errorHandler = function (err, vm, info) {
// 可以捕获的错误
// 1. 组件生命周期钩子里的错误 2.2.0+
// 2. 捕获 Vue 自定义事件处理函数内部的错误 2.4.0+
// 3. 会捕获 v-on DOM 监听器内部抛出的错误 和 Promise 错误 2.6.0+
}
errorHandler(err: Error, vm: Component, info: string) => ?boolean在捕获一个来自后代组件的错误时被调用。 可以通过返回 false 阻止事件的传播
LRU:Least Recently Used,最近最少使用算法
beforeCreate之前做的事情
initLifecycle() 创建$parent $childreninitEvents() 事件监听initRender() 渲染模版beforeCreate之后做的事情
initInjections()initStateinitProvidekeep-alive钩子
activated
deactivated
根据尤大的PPT总结,Vue3.0改进主要在以下几点:
TypeScript + 模块化Composition API 关注点分离 useXXX 优于 mixinsvue2 也提供了一些方法来避免OptionsAPI天生的逻辑碎片化 如下示例
jsmounted: function () {
var picker = new Pikaday({
field: this.$refs.input,
format: 'YYYY-MM-DD'
})
this.$once('hook:beforeDestroy', function () {
picker.destroy()
})
}
本文作者:郭敬文
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!