文章目录
- 一、动态组件``结合v-for循环使用
- 【1】使用环境
- 【2】实际使用
- 【3】编译以后的效果
- 二、watch进阶使用
- 【1】立即执行
- 【2】深度监听
- 三、计算属性之setter
- 四、$on('hook:生命周期')来简化window监听
- 五、子组件@hook:生命周期监听子组件的生命周期回调
- 六、v-pre
- 七、v-once
- 八、Vue.set()
- 九、$forceUpdate()
- 十、keep-alive
- 十一、$route路由信息
- 十二、$route路由信息不刷新问题
- 【1】使用场景
- 【2】解决方案
- 十三、$emit传参同时拿到父子组件两者入参的值
- 十四、样式穿透
- 【1】使用环境
- 【2】实际使用
- 十五、Object.freeze()
- 【1】使用环境
- 【2】实际使用
- 十六、组件通信技巧
- 十七、mixins混入的使用
- 【1】使用环境
- 【2】实际使用
- 【3】注意点(使用的页面统称为组件)
- 十八、qs
- 【1】使用场景
- 【2】实际使用
- 十九、v-for绑定key不建议使用index
- 【1】主要原因
- 【2】解决方案
- 二十、v-for不建议配合v-if
- 【1】主要原因
- 【2】解决方案
- 二十一、document.body.contentEditable
一、动态组件<component :is='组件名'></component>
结合v-for循环使用
【1】使用环境
如图,这是一个v-for渲染的列表(只是目前这个版块才刚开始做,目前只有一个),圆圈内的就是一个组件,也就是要v-for动态组件
【2】实际使用
<template>
<component v-for="(item,index) in componentList" :key="index" :is="item"></component>
</template>
<script>
import ColorIn from '@/components/Magic/ColorIn.vue'
import LineIn from "@/components/Magic/LineIn.vue";
import LineIn from "@/components/Magic/Header.vue";
import LineIn from "@/components/Magic/Footer.vue";
export default{
components:{ColorIn, LineIn, Header,Footer}
}
</script>
【3】编译以后的效果
<ColorIn></ColorIn>
<LineIn></LineIn>
<Header></Header>
<Footer></Footer>
二、watch进阶使用
【1】立即执行
- 使用环境
例如场景为页面一进来就调用拉取列表数据getList(),然后监听路由的$route.query.id然后触发列表数据的更新
- 实际使用
watch:{
'$route.query.id':{
handle(){
this.getList();
},
immediate:true //使用immediate即可立即执行
}
},
created(){
this.getList();
},
【2】深度监听
- 使用环境
在监听对象的时候,对象的内部属性发生变化watch无法监听到,这种时候就需要使用深度监听
- 实际使用
data(){
return{
queryList:{
count:0,
name:'',
}
}
},
watch:{
queryList:{
handle(newValue,oldValue){
//do something
},
deep:true //只需要设置deep:true即可开启深度监听
}
},
三、计算属性之setter
我们一般平常使用的都是getter,但其实它还有个setter,当计算属性的fullName触发更新的时候,就会触发setter回调
data(){
return{
firstName:'',
lastName:'',
}
},
computed:{
fullName:{
get(){
return `${this.firstName} ${this.lastName}`;
},
set(newValue){
let names=newValue.split(' ');
this.firstName=names[0];
this.lastName=names[1];
}
}
},
四、$on(‘hook:生命周期’)来简化window监听
先来看一下平常的使用方法,
mounted () {
window.addEventListener('resize', this.resizeHandler);
},
beforeDestroy () {
window.removeEventListener('resize', this.resizeHandler);
}
改写以后的代码为,相比于上面的写法,这个写法的好处在于可以开启一个事件监听器的同时,就在beforeDestroy生命周期中挂载一个删除事件监听器的事件。比上面的写法会更加安全,更加有助于避免内存泄露并防止事件冲突
mounted () {
window.addEventListener('resize', this.resizeHandler);
this.$on("hook:beforeDestroy", () => {
window.removeEventListener('resize', this.resizeHandler);
})
}
五、子组件@hook:生命周期监听子组件的生命周期回调
<child @hook:mounted="listenChildMounted" />
六、v-pre
不需要编译的html代码可以使用v-pre,可以提高性能
<span v-pre>{{message}}</span> //就算data里面定义了message,渲染完也是{{message}}
七、v-once
只需要渲染一次,适用于渲染完以后就不会更新的内容,降低性能开销
<span v-once>{{message}}</span> //message的值会编译后渲染,但是编译以后再次修改message的值不会触发更新
v-pre与v-once的区别:
v-pre相当于不编译,直接显示,v-once相当于只编译一次,后面的更新不编译了
八、Vue.set()
① 当你利用索引直接设置一个数组项时
② 当你修改数组的长度时
③ 对象属性的添加或删除时
由于Object.defineprototype()方法限制,数据不响应式更新
this.$set(arr,index,item);
九、$forceUpdate()
$set() 也有一定的使用限制,当对象没有这个属性的时候,$set() 就会报错
,这种时候,直接修改数据,再使用 $forceUpdate() 强制视图刷新即可
this.$forceUpdate();
十、keep-alive
【1】当这个页面没有数据更新,或者是想保存状态,下次进来还是这样子的时候,例如淘宝查看列表页,点进去查看详情之后,返回列表页依旧到上次浏览到的地方,都可以使用keep-alive
【2】分为配合路由使用,使用max
,include
,exclude
,以及特殊的生命周期activated
和deactivated
十一、$route路由信息
【1】
$route.query.id
用来拿取路由传值的信息,比如路由的后缀?id=1, r o u t e . q u e r y . i d 拿到的值为 1 【 2 】 ‘ route.query.id拿到的值为1 【2】` route.query.id拿到的值为1【2】‘route.meta.flag用来拿取路由meta中的信息,路由信息里的meta是可以自定义属性的,我一般导航栏当前选中的nav用来和$route.meta.flag进行匹配,来拿到当前页面应该激活哪一个选项卡 【3】
base路由`比方说百度的所有路由前缀要加/baidu,那么可以设置路由的base为/baidu
export const router = new Router({
base:'/baidu/',
}
此外,打包的时候,请修改config/index.js的build块中的assetsPublicPath为 ‘/baidu/’,不然打包以后是找不到资源文件路径的
module.exports = {
build:{
assetsPublicPath: '/baidu/',
}
}
【4】
全局路由钩子
使用场景一般为用户的登录鉴权
router.beforeEach((to, from, next) => {
//一定要调用next()才能到下一个页面
if (path === '/login') {
next()
}else{
if(token){
next();
}else{
next('/login');
}
}
})
【5】
组件路由钩子中访问this
组件路由的钩子一开始还未初始化,不能访问到vue实例
beforeRouteEnter (to, from, next) {
// 这里还无法访问到组件实例,this === undefined
next( vm => {
// 通过 vm 访问组件实例
})
}
十二、$route路由信息不刷新问题
【1】使用场景
有的时候,你从 /user?id=1 跳转到 /user?id=2 的时候,由于渲染同样的 User 组件,导致路由会复用,此时,页面就会仍然是用户1的信息。
【2】解决方案
组件内的路由守卫
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
给 <router-view> 绑定 key
<router-view :key="$route.fullpath"></router-view>
使用watch监听路由
watch:{
'$route':{
hander(){
// do something...
},
immediate:true //如果要首次加载就触发
}
}
十三、$emit传参同时拿到父子组件两者入参的值
在实际项目开发中,可能会遇到 $emit 的值和父组件的index都要拿的情况,但是按照之前的写法,只能拿到其中一个的值,要么子组件,要么父组件,鱼和熊掌不可兼得
- 子组件入参
this.$emit('uploadSuccess',res);
- 父组件入参
<Up @uploadSuccess="uploadLogoImage(index,arguments)" />
- 方法取参
uploadLogoImage(){
console.log(arguments[0]); //index
console.log(arguments[1][0]); //res
},
十四、样式穿透
【1】使用环境
一般在修改插件样式的时候使用的比较多
【2】实际使用
分为两种,一般stylus中使用>>>,less中使用/deep/,sass没有使用经验,不予说明
>>>.el-dialog .el-dialog__body{
padding 0
text-align center
border-radius 0 0 4px 4px
}
/deep/.el-dialog .el-dialog__body{
padding 0
text-align center
border-radius 0 0 4px 4px
}
十五、Object.freeze()
【1】使用环境
我们都知道vue是使用Object.defineProperty对数据进行双向绑定,而对于只做展示使用的长列表,可以使用Object.freeze()进行冻结,使它无法被修改,从而提高性能
【2】实际使用
getList().then(res=>{
this.list=Object.freeze(res.data.result);
})
值得注意的是,改变list的值不会更新,但改变引用会触发更新
十六、组件通信技巧
- props
- $emit
- $attrs & $listeners
- provide & inject
- vuex
- Observable
- eventBus
- $refs
- slot-scope & v-slot
- scopedSlots
- $parent & $children & $root
十七、mixins混入的使用
【1】使用环境
一般获取验证码,收藏,点赞等公用且逻辑一样(有些逻辑是根据页面的不同而不同的不建议使用混入)等场景都可以使用混入
【2】实际使用
这里我直接封装了一个vue新开窗口的混入方法,引入了以后,混入中的所有data,methods,以及生命周期都会共享
//openWindow.js
export default {
methods:{
openUrl(url){
const link= this.$router.resolve({path: url});
window.open(link.href,'_blank');
},
}
}
//其他页面使用
import openWindow from "../../mixins/openWindow";
export default{
mixins:[openWindow],
}
【3】注意点(使用的页面统称为组件)
① 混入比组件优先执行
② 当混入中的属性或者方法与组件中的属性或者方法名称相同时,以组件中的值为准(结合上一条规则,因为混入先执行,所以组件会将混入覆盖)
③ 比方说A页面和B页面都使用了同一个混入,A页面与B页面的状态同样是独立的
十八、qs
【1】使用场景
get传输的时候都是路由拼接方式(?a=1&b=2),而不是json方式
【2】实际使用
//安装依赖
npm install qs --save
//页面中或者直接api.js中直接序列化使用
import qs from 'qs'
qs.stringify(params)
//axios拦截器中直接使用
import qs from 'qs'
axios.interceptors.request.use(
config => {
if (config.method === 'get') {
config.data = qs.stringify(config.data)
}
)
十九、v-for绑定key不建议使用index
【1】主要原因
有的时候v-for列表可能存有删除,交换位置等操作,这种时候index的顺序变换会导致同一条数据,在此刻的index置换,所以,不建议v-for的key绑定index
【2】解决方案
建议使用另外的并且值唯一的变量,例如后台给你的id,反正只要是唯一,不会重复即可
二十、v-for不建议配合v-if
【1】主要原因
v-for的优先级比v-if高,也就是说,假设总计50条数据,即使经过v-if以后,只剩下25条显示,但是v-for早就循环了一遍50条数据,解决办法就是用一个计算属性先将数据过滤了以后,v-for循环过滤了之后的数据
【2】解决方案
使用 computed 计算属性,对列表进行过滤,只剩下过滤之后需要的数据
二十一、document.body.contentEditable
操作方法:
打开控制台,输入document.body.contentEditable=true,然后敲回车,网页可以像word一样编辑,很方便对于页面的布局抗压能力做测试
javascript: (function () {
if (document.body.hasAttribute('contentEditable')) {
document.body.removeAttribute('contentEditable');
} else {
document.body.contentEditable = true;
}
})();