vue小细节
1. 组件缓存 keep-aive 属性 exclude
include - 字符串或正则表达式。只有名称匹配的组件会被缓存
exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例。
<keep-alive exclude="Detail">
<router-view />
</keep-alive>
2. es6加载路由组件
const Detail = () => import('../views/detail/Detail.vue');
3.避免路由跳转报错
//replace 避免报错 const VueRouterReplace = VueRouter.prototype.replace VueRouter.prototype.replace = function replace(to) { return VueRouterReplace.call(this, to).catch(err => err) } //push 避免报错 const VueRouterPush = VueRouter.prototype.push VueRouter.prototype.push = function push(to) { return VueRouterPush.call(this, to).catch(err => err) }
4.声明组件名
2. 定义一个子组件想引用vue实例中的data 属性,在做属性绑定的时候使用了驼峰,结果拿不到值,我这个使用的是线上的版本利用vue-devtools 发现props中的dataMsg为undefined,这个时候的改为datamsg就正确了
3.组件之间通信 , 传递对象属性的value值 , 需要用wacth来监听 props接收到的值 , 不然为undefined
5.组件点击 @click.native
<back-top @click.native="backClick" v-show="isBackShow"></back-top>
6.this.$refs获取子组件相关 , 改变子组件数据
<tab-control :titles="[{ title: '流行' }, { title: '精选' }, { title: '新款' }]" @itemClick="tabClick" ref="tabControl1" v-show="isFixed" ></tab-control> //子组件 this.$refs.tabControl1.courrentIndex = index; //改变子组件数据 this.$refs.tabControl1.$el.getBoundingClientRect() .top //获取子组件距离顶部高度
7.具名插槽 , 类名不要用 中划线 来间隔
8.Vuex,每次调用mutation之后向localstorage存值,防止刷新丢失
9.vue.config.js 每次更改完之后需要重新启动项目
10. 用样式穿透来解决ui框架后引入导致样式覆盖问题 .home >>> .children
11.vue使用this.$refs.xx在mounted中获取DOM元素为undefined
12.使用 @hook 即可监听组件生命周期,组件内无需做任何改变
<template>
<List @hook:mounted="listenMounted" />
</template>
13.手动挂载组件
import vue from 'vue' import Message from './Message.vue' // 构造子类 let Messageconstructor = vue.extend(Message) // 实例化组件 let messageInstance = new Messageconstructor() // $mount可以传入选择器字符串,表示挂载到该选择器 // 如果不传入选择器,将渲染为文档之外的的元素,你可以想象成 document.createElement()在内存中生成dom messageInstance.$mount() // messageInstance.$el获取的是dom元素 document.body.appendChild(messageInstance.$el)
14.wacth高阶使用
14-1.在组件创建后 watch 属性immediate设置为true 能够立即执行
export default { data() { return { name: 'Joe' } }, watch: { name: { handler: 'sayName', immediate: true } }, methods: { sayName() { console.log(this.name) } } }
14-2.在监听对象时,对象内部的属性被改变时无法触发 watch , 设置属性deep为true , 为其设置深度监听
export default { data: { studen: { name: 'Joe', skill: { run: { speed: 'fast' } } } }, watch: { studen: { handler: 'sayName', deep: true } }, methods: { sayName() { console.log(this.studen) } } }
14-3 触发监听执行多个方法
export default { data: { name: 'Joe' }, watch: { name: [ 'sayName1', //字符串形式 function(newVal, oldVal) { //函数形式 this.sayName2() }, { //对象形式 handler: 'sayName3', immaediate: true } ] }, methods: { sayName1() { console.log('sayName1==>', this.name) }, sayName2() { console.log('sayName2==>', this.name) }, sayName3() { console.log('sayName3==>', this.name) } } }
14-4 wacth监听多个变量
watch本身无法监听多个变量。但我们可以将需要监听的多个变量通过计算属性返回对象,再监听这个对象来实现“监听多个变量”
export default { data() { return { msg1: 'apple', msg2: 'banana' } }, compouted: { msgObj() { const { msg1, msg2 } = this return { msg1, msg2 } } }, watch: { msgObj: { handler(newVal, oldVal) { if (newVal.msg1 != oldVal.msg1) { console.log('msg1 is change') } if (newVal.msg2 != oldVal.msg2) { console.log('msg2 is change') } }, deep: true } } }
14-4 注销 watch
const unWatch = app.$watch('text', (newVal, oldVal) => {
console.log(`${newVal} : ${oldVal}`);
})
3.如何注销?
const unWatch = app.$watch('text', (newVal, oldVal) => {
console.log(`${newVal} : ${oldVal}`);
})
unWatch(); // 手动注销watch
app.$watch调用后会返回一个值,就是unWatch方法,你要注销 watch 只要调用unWatch方法就可以了。
15.函数式组件:
一般适合只依赖于外部数据的变化而变化的组件,因其轻量,渲染性能也会有所提高。
创建函数式组件也很简单,只需要在模板添加 functional 声明即可
子组件
<template functional>
<div class="list">
<div class="item" v-for="item in props.list" :key="item.id" @click="props.itemClick(item)">
<p>{{item.title}}</p>
<p>{{item.content}}</p>
</div>
</div>
</template>
父组件
<template>
<div>
<List :list="list" :itemClick="item => (currentItem = item)" />
</div>
</template>
import List from '@/components/List.vue'
export default {
components: {
List
},
data() {
return {
list: [{
title: 'title',
content: 'content'
}],
currentItem: ''
}
}
}
16.路由参数解耦
将路由的 props 属性设置为 true 后,组件内可通过 props 接收到 params 参数
const router = new vueRouter({ routes: [{ path: '/user/:id', component: User, props: true }] })
另外还可以通过函数模式来返回 props
const router = new vueRouter({ routes: [{ path: '/user/:id', component: User, props: (route) => ({ id: route.query.id }) }] })
可通过 props 接收参数
export default { props: ['id'], methods: { getParamsId() { return this.id } } }
16.params传参问题
params传参时,如果没有在路由中定义参数,也是可以传过去的,同时也能接收到,但是一旦刷新页面,这个参数就不存在了。
这对于需要依赖参数进行某些操作的行为是行不通的.
// 定义的路由中,只定义一个id参数 { path: 'detail/:id', name: 'Detail', components: Detail } // template中的路由传参, // 传了一个id参数和一个token参数 // id是在路由中已经定义的参数,而token没有定义 <router-link :to="{name: 'Detail', params: { id: 1, token: '123456' }}">前往Detail页面</router-link> // 在详情页接收 created () { // 以下都可以正常获取到 // 但是页面刷新后,id依然可以获取,而token此时就不存在了 const id = this.$route.params.id; const token = this.$route.params.token; }
17.定时器问题
通过$once这个事件侦听器器在定义完定时器之后的位置来清除定时器
const timer = setInterval(() =>{ // 某些定时器操作 }, 500); // 通过$once来监听定时器,在beforeDestroy钩子可以被清除。 this.$once('hook:beforeDestroy', () => { clearInterval(timer); })
18.props验证
props: { status: { type: String, //数据类型 required: true, //是否验证 validator: function (value) { //验证函数 return [ //验证结果 'success', 'error', ].indexOf(value) !== -1 } } }
19.路由组件复用
在开发当中,有时候我们不同的路由复用同一个组件,默认情况下,我们切换组件,Vue出于性能考虑可能不会重复渲染。
但是我们可以通过给router-view绑定一个key属性来进行切换的时候路由重复渲染。
<template>
<router-view :key="$route.fullPath"></router-view>
</template>
20批量属性继承
使用$props将父组件的所有的props传递到子组件
场景 : 从父组件接收传递下来的数据使用props接收,再将这些props数据传递到子组件
<template>
<!-- 将从父组件接收到的props数据传递到子组件
使用v-bind="$props" 批量传递
-->
<childComponent
v-bind="$props"
/>
</template>
<script>
export default {
// 从父组件接收到的props数据
props: ['value1','value2','value3','value4','value5'],
data() {
return {....}
.....
}
}
// childComponent.vue
<script>
export default {
props: ['value1','value2','value3','value4','value5'],
data() {
return {....}
.....
},
mounted() {
// 子组件可以接收到数据
console.log(this.value1)
console.log(this.value2)
console.log(this.value3)
console.log(this.value4)
console.log(this.value5)
}
}
</scrript>
属性继承在开发表单组件时,使用$props就可以很好的解决批量属性传递问题。
21.组件懒加载(异步加载组件)
1.为什么要用
所有的组件代码都会在首次渲染是下载 , 体验不佳
2.什么场景用
比如后台管理页面,在多个tab之间切换的时候,其余tab里面的组件就可以在需要的时候再异步加载~
有多个子路由的页面必用
3.如何用?
components: { test: () => import("./Test.vue") },
给加载js命名
components: { test: () => import(/* webpackChunkName:'test' */ "./Test.vue"), //给加载js命名 },
处理加载状态的写法
异步组件工程函数
const AsyncTest = () => ({ component: import(/* webpackChunkName:'test' */ "./Test.vue"), loading: LoadingComponent, //加载时显示的组件 error: ErrorComponent, //超时或错误时显示的组件 delay: 200, //延迟 timeout: 3000, //超时 });
22.解决async/await异步问题
使用 await 1; 解决异步
例子:
async created(){ try { //捕获await错误信息 this.couponArr = await this.getData({form_id:11,pageSize:9}).then(res=>{ if(res.length>8){ res.pop(); this.couponBtn=true; return res; } return res; }); this.storeArr1[this.currentIndex]= await this.getData({form_id:8,position_ename:'nav1-1',pageSize:4}); this.currentArr = this.storeArr1[this.currentIndex]; this.storeArr2 = await this.getData({form_id:18,pageSize:5}).then(res=>{ if(res.length>4){ res.pop(); this.bandanBtn=true; return res; } return res; }); this.storeArr3 = await this.getData({form_id:8,position_ename:'nav3'}); } catch (e) { console.log(e) } await 1; //解决异步 this.gundong() this.navFixed({ navParent: '.nav_box', nav: '.nav', navItem: '.nav li', itemParent: '.tit', active: 'active', fixedTop: '0', deviation: parseFloat($('.nav').height()), animateTime: 500, flag: 0 }) this.tab() this.xuanran(); this.videoHandle(); this.gtOrltVisible() this.swiperHandle() this.staticImg() },
23.滚动节流
passive: 是告诉浏览器,监听器不会调用e.preventDefault()函数,不用来检查,可以提前生成手势,从而提高流畅性,通常用在move事件中
例子:
<template>
<div class="scroll">
<div class="containers" @scroll.passive="scrollHandle">
<div class="content">
<ul>
<li v-for="item in 100">{{ item }}</li>
</ul>
</div>
</div>
</div>
</template>
<script>
export default {
name: "Scroll",
components: {},
data() {
return {
scrollHandle: () => {},
};
},
created() {
this.scrollHandle = this.throttle(this.scrollHandle2, 200);
},
methods: {
scrollHandle2(e) {
console.log(456);
},
throttle(func, delay = 800) {
let lock = false;
return (...args) => {
if (lock) {
return;
}
func(...args);
lock = true;
setTimeout(() => {
lock = false;
}, delay);
};
},
},
};
</script>
<style scoped >
.containers {
height: 500px;
border: 1px solid #000;
overflow: scroll;
}
</style>
24.$destroy()方法问题
某种业务场景下,我们期望缓存的页面可以被销毁,就会调用$destroy方法,这回导致被销毁的页面,虽然会触发activated钩子函数,但是页面实际上没有被缓存,重新进入是初始dom结构的状态。
24.数据更新,update()/beforeUpdate()未触发问题
页面使用到的数据改变时才会更新 updated 和 beforedate钩子函数
24.vue-router中params传值问题
1.path定义了动态传值 , 则params为必传项 , 否则router-view不显示
router/index.js
{ path: '/park1/:id', name: 'park1', component: () => import( /* webpackChunkName: "about" */ '../views/park1.vue') }
.vue文件
或者 路径拼接 :to="'/park1/'+1"
1.如果是用name来匹配路由
相当于post请求,参数不会再地址栏中显示。
存在页面刷新, params返回参数会丢失 , query并不会出现这种情况
拓展:解决用name来匹配路由页面,刷新params丢失问题
1.使用query传递数据
2.将数据在前一页存到 localstoratgel里
存数据
router.beforeEach((to, from, next) => { //通过该方式可以保存 VueRouter 的数据不被刷新 localStorage.setItem('routerParams', JSON.stringify(to.params)); next() })
取数据
created() { //如果是被keep-alive 标签包裹 , 可以在activated 钩子函数中获取参数
this.params = JSON.parse(localStorage.getItem("routerParams")); },
25.props规范
数组形式来接收数据 ,开发时的工作量会小一些 , 但不推荐 , 不利于后续维护项目
props:['name','type','list']
建议使用对象形式 ,
props:{
name: String, //字符串类型 type: { validator: function(value) {//这个值必须匹配下列字符串中的一个 return ["success","warning","danger"].includes(value);
}
},
list: {
type: Array,
//对象或数出默认值必须从一个工厂函数获取
default: O)→>[]
},
}
26. v-for循环时 , 可以直接通过传入对象直接更改 , 不用传下标然后找到数组中对应对象 , 再进行修改
例子:
<template>
<div>
<ul>
<li v-for="item in data" :key="item.id">
<button @click="add(1, item)">+</button>
<span>{{ item.num }}</span>
<button @click="add(-1, item)" v-if="item.num > 0">-</button>
</li>
</ul>
</div>
</template>
<script>
export default {
props: {},
data() {
return {
data: [
{
num: 0,
id: 0,
},
{
num: 100,
id: 2,
},
{
num: 99,
id: 3,
},
],
};
},
components: { list },
created() {},
mounted() {},
methods: {
add(num, v) { //直接对传入的数组对象进行修改 , data数组中的对象的value值也会修改
v.num += num;
},
},
watch: {},
computed: {},
};
</script>
<style scoped lang="less">
</style>
27. computed中不要使用箭头函数
28. 更新组件
更新组件上传入的key即可,用 new Date().getTime()
<a-popover placement="bottomRight" :key='showPopoverKey'> data() { return { showPopoverKey:new Date().getTime(), } }, methods: { clickUpdate(){ //点击更新组件 this.showPopoverKey:new Date().getTime() } }
29. data赋值
已antd vue为例:
this.form.validateFields((errroe, values) => { if (!errroe) { Object.assign(this, values); } });
30. 重置路由
解决vue-router中的缓存问题
// 替换现有router的routes router.matcher = new VueRouter({ routes: newRoutes }).matcher
31. 根组件绑定bus
//根组件绑定
new Vue({ render: h => h(App), data() { return { bus: new Vue() } }, router, store }).$mount('#app') //使用 //A组件订阅 this.$root.bus.$on('fromUpdate', () => { this.getTableList() }) //B组件发布 this.$root.bus.$emit('fromUpdate')
32. filters中获取this
<template>
<div>{{a|sum(that)}}</div>
</template>
<script>
export default {
name: "test",
data() {
return {
that: this,
a: 1,
b: 2
}
},
filters: {
sum(a, that) {
console.log(that);
return a + that.b;
}
},
}
33.解决$on多次被调用
this.$baseEventBus.$off('setColor') this.$baseEventBus.$on('setColor', colorObj => { console.log(colorObj ) })
34.解决重置data
直接赋值: this.$data = this.$options.data()
报错:Avoid replacing instance root $data. Use nested data properties instead
原因:如果你的vue实例的data方法里通过this引用了其他vue实例上的方法/属性等,需要改成下面这样,修复this指向问题导致的报错。
解决方案
Object.assign(this.$data, this.$options.data.call(this));
35.点击按钮选择文件
<input type="file" ref="inputFile" accept=".xls,.xlsx,.txt" @change="readFile($event)" style="display: none" />
36.jsx绑定点击事件并传参
jsx写法示例
<span class="yuan" onClick={() => this.connectRight(row)}></span>
37.watch 只监听一次
mounted() { const unwatch = this.$watch("needWatch", function (val) { // 处理业务逻辑 // 之后调用unwatch, 取消监听 unwatch(); }); },
38.route参数更新
直接修改 $route.query.id = 111, 页面 url 未更新,
...

浙公网安备 33010602011771号