1.keep-alive
在使用keep-alive包裹动态组件时,会缓存不活跃的组件实例 ,在生命周期中会新增两个钩子函数activated和deactivated
activated触发时机:keep-alive组件激活时使用,在生命周期创建后(created)和挂载后(mounted)被调用(钩子触发顺序created->mounted->activated,当我们运用了组件缓存时,如果想每次切换都发送一次请求的话,需要把请求写在activated中,而写在created或mounted中只会在首次加载该组件的时候起作用) deactivated触发时机:keep-alive组件停用时调用
使用include和exclude时,组件要写name属性 export default{name:"domeName",......},还有一个参数max(最多缓存几个)
原理:在电脑内存中创建一个代码片段,把包含的组件筛进内存里面,切过去再切回来时从内存中把存进去的代码取出来渲染,而不用再去从服务器读取,效率快
2.mvvm
mvvm是一种架构模式(设计模式)m是model数据模型,v是view视图,vm是ViewModel视图模型,vm对m的数据有绑定挟持机制对v中有监听机制,使用Object.defineProperty递归挟持Vue实例对象data中的所有数据,对所有数据的访问就getter和setter代理了,当我们改变数据,就会触发setter函数,Vue的底层就会通知视图更新渲染 只要m中数据变化,就会通知视图更新渲染,只要视图有用户有输入,就会同步到m中;
m相当于vue中的data,v相当于template,vm相当于Vue实例对象(export default{})
观察者模式:设计模式 【了解】
初始化代码的时候,Vue的底层有一个observe 把所有数据都挟持了, 有一个订阅者Dep 和一个观察者Watcher ,Dep实现把访问过的属性收集起来了,当数据改变,触发setter,Dep通知观察者,说数据变化了,观察者调用更新方法,进行数据的更新,通知视图进行渲染。
js
<div id="app"></div>
<script>
//m
let data={msg:"消息"}
//v
function renderFn(){
app.innerHTML=`<input oninput="handleIpt(this)" value="${data.msg}"><span>${data.msg}</span>`
}
renderFn()
let _msg=data.msg
//vm Object.defineProperty
Object.defineProperty(data,"msg",{
get(){return _msg},
set(newVal){
_msg=newVal
watch()
}
})
function watch(){
renderFn()
}
//视图有输入更新同步到m中
function handleIpt(e){
data.msg=e.value
}
</script>
//Vue3的底层实现:底层使用ES6新增的代理对象proxy
const o=new Proxy(data,{
get(target,property){
return target[property]
}
set(target,property,newVal){
target[property]=newVal
}
})
function watch(){
renderFn()
}
function handleInput(input){
data.msg=input.value
}
3.自定义v-model
js
//名为 value 的 prop 和名为 input 的输入事件
//<input v-bind:value="val" v-on:input="val = $event.target.value" />
<template>
<son :value="val" @input="val=$event"></son>
<span>{{val}}</span>
</template>
<script>
import Son from "./son.vue"
erport default{
data(){
return{
val:"父的默认值"
}
},
components:{
Son
},
}
</script>
//-------------子组件--------------
<template>
<input :value="value" @input="handelIpt" />
</template>
<script>
erport default{
data(){
return{
}
},
props:{
value:{
type:String
required:false
default:"不传默认值就是我"
}
},
methods:{
handelIpt(e){
this.$emit("input",e.target.value)
}
}
}
</script>
4.data为什么是一个函数?
一个组件的data选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝 。如果data是一个对象,多个组件(实例对象)就会共享这份数据,组件data之间指向了同一内存地址 ,造成一个变了全都会变的结果。当data是一个函数时,组件实例化时会调用这个函数,返回一个新的对象,分配一个新的内存地址 ,地址不一样,数据就不会互相干扰,保证了组件的独立性和可复用性。
5.计算属性computed和侦听器watch
computed主要用于逻辑计算,返回唯一结果,有依赖缓存 ,依赖的数据发生变化才会重新计算。使用的函数名就是函数返回的结果。(购物车)watch主要用于观察数据的变化,执行关联操作(面包屑,搜索栏);methods是方法,一般用于事件绑定的处理函数和函数调用,函数调用某些场景不一定需要返回值。
Vue源码:执行加载顺序Props-->Methods-->Data-->Computed-->Watch
js
export default{
data(){
return{
}
},
computed:{
函数名(){
return 结果
}
//第一种
name() {
return this.firstName + ' ' + this.lastName
}
//第二种
name: {
get() {
return this.firstName + " " + this.lastName;
},
set(newVal) {
let t = newVal.split(' ')
this.firstName = t[0]
this.lastName = t[1]
},
}
},
watch:{
//第一种
"观察的数据"(newVal,oldVal){
console.log(newVal,oldVal) //执行的操作
},
//第二种
"isCheeckName":{
//处理的函数,只要观察到isCheeckName变化,就会触发hander函数
hander(newVal,oldVal){
console.log(newVal,oldVal) //执行的操作
},
deep:true,//开启深度观察
immediate:true//该回调将会在侦听开始之后被立即调用一次
}
},
methods:{
//调用需要(),不一定有返回值,没有依赖缓存,每次调用,就会重新执行里面的所有代码
},
}
6.# this.$nextTick,this.set
js
//在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM
//created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中
this.$nextTick(() => {
// 更新数据 dom更新渲染完成 就会触发
console.log(document.querySelectorAll('li'))
})
//Vue初始化的时候,只会挟持data中的数据, 不会挟制数组, 所以,如果给对象添加新数据或修改数据的数据, 都不会触发视图更新,使用Vue.set可以重新挟持数据,让数据具备响应式。
this.$set(对象, 属性名, 新的值)
this.hobs.splice(1, 1, 'Vue')
this.$set(this.hobs, 1, 'React')
7.实例属性
js
//$refs,$parent,$children,$attrs,$listeners,$el
<template>
<div ref='box'></div>
</template>
mounted(){
this.$refs.box//<div data-v-048022ad></div>//获取DOM
}
methods:{
//$parent 既 可 以 接 受 父 组 件 数 据 , 又 可 以 修 改 父 组 件 数 据, 是 双 向 的
//$parent 可以调用父组件的方法
//想在子组件里获取父组件的元素之类的,必须使用nextTick
parentPrint(){
this.$nextTick(() => {
this.$parent.fn()
})
this.$parent.data='操作父组件的属性'
}
}
$children 当前实例的直接子组件
$attrs 拿绑定到子组件标签上的属性(排除: props接收的 ,class、style)
$listener 拿绑定到子组件标签上的事件(排除: .native)
$el 提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标
$root 获取根组件的实例对象
provide选项应该是一个对象或返回一个对象的函数, 可以提供数据。
inject选项,可以把祖辈组件,提供的数据,注入进入当前组件。
8.插槽v-slot
分为匿名插槽,具名插槽,自定义插槽
js
//插槽主要在子组件预留位置,父组件把内容插入,实际的用途主要用于组件的封装,内容可以自定义
//匿名插槽
<div>
<span>非插槽内容</span>
<slot>我是匿名插槽默认值</slot>
<slot name="conName">我是具名插槽默认值,想插进来必须带上名字</slot>
</div>
//------作用域插槽,可以写名字也可以不写名字
<template>
<slot :title="title" msg="小貂禅">我是作用域插槽默认值</slot>
</template>
title="作用域"
js
<model>
<p>沃斯插入插槽的内容</p>
<span slot="conName">我是插入具名插槽的内容<span>
</model>
//----------作用域插槽
<model slot-scope="scope">
<p>{{scope.title}}</p>
<p>{{scope.msg}}</p>
<i>我是作用域插槽插进去的东西</i>
</model>
import Model from "@/components/model/Model.vue"
9.minin混入
如果有相同选项,用自己的;抽取公共配置项,自由简单,容易混乱,难以维护
js
//定义一个混入对象
export const myMixin={
data(){
return{
msg:"唱跳"
}
},
created(){
this.hello()
},
methods:{
hello(){
console.log("沃斯混入进来的")
}
}
}
js
import { myMixin } from "@/mixin/index.js"
export default{
mixins:[myMixin]//混入
}
10.动态组件component :is
js
//场景:局部选项卡切换,多个组件使用同一个挂载点并且动态切换
//<component :is="你具体要显示那个组件的变量"> </component>
<template>
<div>
Home页面
<button @click="fun('One')">点我去one</button>
<button @click="fun('Two')">点我去two</button>
<button @click="fun('Three')">点我去three</button>
<component :is="com"></component>
</div>
</template>
<script>
import One from "@/components/one.vue"
import Two from "@/components/two.vue"
import Three from "@/components/three.vue"
export default {
data(){
return {
com:"Three"
}
},
methods:{
fun(data){
this.com = data
}
},
components:{
One,Two,Three
}
}
</script>
//可以配合keep-alive使用
11.异步组件
js
components:{
//异步组件
'jl-button':()=>import("@/components/jlButton.vue")
}
12.内置组件
- keep-alive
- slot
- component
- transition 动画
js
<!-- 内置的动画组件 把我们要做动画的组件包裹起来 -->
<transition name="fade">
<jl-model @close="visible=false" v-show="visible"></jl-model>
</transition>
// 进入动画的过程 和 离开动画的过程
.fade-enter-active, .fade-leave-active {
// 过渡
// transition: opacity 5s;
transition: all 0.3s;
}
// 进入的瞬间 离开的瞬间
.fade-enter, .fade-leave-to {
// opacity: 0;
transform: translateX(-100%);
}
13. 递归组件
组件内部,自己使用自己,就是递归组件,常见的就是: 菜单树, 注意:组件要给name,才可以。 组件给name的作用:
- 递归组件,可以自己在模板中使用自己
- keep-alive缓存组件
14.全局组件Vue.component
js
//创建一个filters文件夹下面的index.js
//首字母大写
export function firstUpperCase(value){
return value.slice(0,1).toUpperCase()+value.slice(1)
}
//千分位逗号隔开
export function thousand(value){
return value.replace(/(?=(\B)(\d{3})+$)/g,",")
}
//main.js
//第一种 高阶
//引入过滤器函数们
import * as filters from "@/filters"
//循环
Object.keys(filters).forEach(key=>{
//自动注册为全局过滤器
Vue.filter(key,filters[key])
})
//第二种
Vue.filter("fixed2",(value)=>{return value.toFixed(2)})
//组件中使用
<template>
<p>{{666|fixed2}}</p>
<p>{{"hello"|firstUpperCase}}</p>
<p>{{"54088"|thousand}}</p>
</template>
15.全局自定义指令directive
js
//main.js
Vue.direactive("ellipsis",{
//当被绑定的元素插入到DOM中时
inserted(el,expr){
el.style.width=expr.value+"px"
el.style.overflow="hidden"
el.style.whiteSpace="nowrap"
el.style.textOverflow="ellipsis"
}
})
//第二种高阶写法跟全局过滤器基本一致
<template>
<p v-ellipsis="99">沃斯敲键盘两年半的cv工程师</p>
</template>
//管理系统按钮级的权限高级写法就可以用全局自定义指令,简单就用v-if也可以