1. 基本指令
v-bind
操作元素的class列表和内联样式是数据绑定的一个常见需求,所有我们可以使用v-bind处理它们
1. 绑定class介绍
<!-- 1. 对象语法 -->
<script>
// 绑定class的两种方式,对象语法,数组语法
const isActive = true
const classObj = {
active: true,
title: true
}
</script>
<style>
.active {
color:red;
}
</style>
<div :class="{ 'active': isActive}"></div>
<!-- 也可以多个键值对 -->
<div :class="{active: isActive, title: true}">
<!-- 默认的class和动态class结合 -->
<div class="abc dic" :class="{active: isActive}">
<!-- 将对象放到单独的属性中 -->
<div class='abc cba' :class="classObj">
<!-- 2. 数组语法 -->
<div :class="['abc',title]"></div>
<div :class="['abc',title, isActive ? 'active' :'']"></div>
<div :class="['abc',title, {active: isActive}]"></div>
<script>
// 绑定class的两种方式,对象语法,数组语法
const isActive = true
const classObj = {
title: 'bcd',
isActive: true
}
</script>
2. 绑定 style 介绍
<!-- 1.对象语法 -->
<div :style="{color: finalColor, 'font-size': '30px'}">
<div :style="{color: finalColor, fontSize: '30px'}">
<div :style="{color: finalColor, fontSize: finalFontSize + 'px'}">
<!-- 绑定一个对象 -->
<div :style="finalStyleObj">
<!-- 绑定一个方法 -->
<div :style="getFinalStyleObj()">
return {
finalColor: 'red',
finalFontSize: 20,
finalStyleObj: {
color: 'red'
}
}
<!-- 2.数组语法 -->
<div :style="[styleObj, style2Obj]">
return {
styleObj: {
color: 'red',
fontSize: '20px'
},
style2Obj: {
text: '2'
}
}
3. v-bind 动态绑定属性名称
<div :[name]="value"></div>
<script>
return {
name: 'cba',
value: 'kobe'
}
</script>
4. v-bind 属性直接绑定一个对象
<div v-bind="info"></div>
<script>
const info = {
name: 'why',
age: 18,
height: 1.99
}
</script>
v-on的修饰符
1. .stop 调用event.stopPropagation()
2. .prevent 调用 event.preventDefault()
3. .capture 添加事件监听器时使用capture模式
4. .self 只当事件是从监听器绑定的元素本身触发时才会触发回调
5. .{keyAlias} 仅当事件是从特定触发时才会触发回调
6. .once 只触发一次回调
7. .left 只当鼠标左键时触发
8. .right 只当鼠标右键时触发
9. middle 只当鼠标中建时触发
10. passive { passive: true } 模式添加监听器
<!-- 修饰符的使用 -->
<button @click.stop="abx">
v-model
v-model指令可以在表单 input,textarea以及select元素创建双向绑定
会根据控件类型,自动选取正确的方法来更新元素
// lazy修饰符
1. 默认情况下,v-model在进行双向绑定,绑定的是input事件,那么每次内容输入后,就会将值和绑定的属性进行同步
2. 加上lazy后,那么就会绑定事件切换为change事件,只在提交时触发
// .number
1. 只会截取数字,并存入数字类型
// .trim
1. 会截去字符串前后空格
组件的 v-model
<--父组件-->
<my-input v-modul="modelVlaue"></my-input>
<my-input :modelVlaue="modelVlaue" @update:modelValue='$event'>
给组件绑定v-model等同于 下面这种写法
</my-input>
// 绑定多个v-modul
<my-input v-modul="modelVlaue" v-modul:title="title"></my-input>
<script>
data() {
return {
modelVlaue: 'Hello Wrold'
}
}
</script>
<--子组件-->
计算属性方式
<input v-model="value">
方法实现
<input :value="modelValue" @input="btnClick">
<script>
props: {
modelValue: String,
modelTitle: String,
},
emits: ['update:modelValue','update:modulTitle'],
computed: {
value: {
get() {
retrun this.modelValue
},
set(value) {
this.$emit('update:modelValue',value)
},
}
},
methods: {
btnClick(event) {
this.$emit('update:modelValue',event.target.value)
}
}
<script>
v-if v-else v-else-if
1. 只有内容再条件为true才会渲染
2. v-if 是惰性的 为false时,判断的内容完全不会被渲染,会被销毁
3. 当为true时,才会真正渲染条件快中的内容、
4. 因为v-if 是一个指令,必须添加到元素上 此时我们渲染div,但是我们并不希望div这种元素被渲染,我们可以使用 <template>
v-show
1. 和v-if一样
2. 不同的是,当为false时,相当于display:none
3. 不支持template v-show不能与v-else一起使用
v-for
1. 格式 item in 数组(也可以of)
2. 数组通常来自data或者prop item是取的别名
<!-- item 是每一项 index是索引 -->
<div v-for="(item,index) in data">
<!-- 遍历对象 key是建 -->
<div v-for="(item,key,index) in {name:'red'}">
<!-- 遍历数字 -->
<div v-for="(item,index) in 10">
2. vue2 OptionsApi
computed(计算属性)
1. 对响应式数据的复杂逻辑,应该使用计算属性
2. 计算属性将被混入组件实例中,所有getter和setter的this上下文自动绑定组件实例
3. 计算属性是有缓存的,当多次使用计算属性时,计算属性中的云算只会执行一次
4. 计算属性也是响应式的
computed 和 methods 的区别
computed 是有缓存的 methods没有,每次使用都会执行一次
<!-- 直接当属性使用,不需要加()当函数调用 -->
<div>{{fullName}}</div>
<script>
const firstName = 'kobe'
const lastName = 'Bryant'
computed: {
fullName() {
return this.firstName + " " + this.lastName
}
}
</script>
<!-- computed的getter和setter方法 -->
<!-- 当写成函数形式时,只执行get方法,当写成对象时,可以配置set方法 -->
<!-- 当调用计算属性时,给计算属性赋值,就会调用set方法 -->
<script>
data() {
return {
firstName: 'kobe',
lastName: 'Bryant'
}
}
computed: {
fullName: {
get: function() {
return this.firstName + " " + this.lastName
},
set: function(newValue) {
const names = newVlaue.split(' ')
this.firstName = names[0]
this.lastName = names[1]
}
}
},
methods:{
this.fullName = "coder Why"
}
</script>
watch(监听器)
当数据变化时,我们希望在代码逻辑中监听某个数据的变化,就可以使用侦听器watch完成
<script>
data() {
return {
question: 'Hello World',
anwser: '',
info: { name: 'why', age: 18}
}
}
methods: {
queryAnswer(){
}
},
// 这是跟对象
watch: {
question(newValue,oldVlaue) {
// question 是侦听的data中的属性名称
// newValue 是变化后的新值
// oldVlaue 是变化前的旧值
this.queryAnswer()
},
// 当需要添加配置时,跟对象
info: {
handler: function(newValue,oldVlaue) {
return console.log(newValue,oldVlaue)
},
deep: true, // 深度监听
immidiate: true // 当页面刷新,立即执行一次
},
// 侦听对象里某个属性时
'info.name': function(newName, oldName) {
console.log(newName.oldName)
}
}
// 侦听器的其他用法
created() {
// 我们可以在created中使用this.$watch来侦听
// 第一个参数是侦听对象,第二个是回调函数,第三个是配置对象
const unwatch = this.$watch('info',(newVlaue,oldInfo) => {
console.log(newValue,oldInfo)
},{
deep: true,
immediate: true
})
unwatch() // 当调用时,取消侦听器
}
</script>
组件通信
1. 父组件传递给子组件: 通过props属性
// 什么是Props
`Props是你在组件上注册一些自定义的attribute
父组件给这些attribute赋值,子组件通过attribute的名称获取对应的值`
// Props的用法
// 1. 字符串数组, 数组中的字符串就是attribute的名称
Props: ['title', 'content']
// 2. 对象类型, 对象类型我们可以在指定attribute名称的同时,指定它需要传递的类型,是否必须,默认值等
Props: {
title: String,
content: {
type: Number, // 类型
required: true, // 必传
default: '123' // 默认值
}
}
// 自定义验证函数
propF: {
validator(value) {
// 这个值必须匹配下列字符串中的一个
return ['success','warning'].includes(value)
}
}
2. 子组件传递给父组件: 通过$emit触发事件
`子组件`
<button @click="addNum">+1</button>
// 1. 先注册事件
emits: ['add','sub']
// 对象写法的目的为了进行参数验证
emits: {
add: null,
sub: (num) => {
if(num>10) {
return true
}
return false
}
}
// 2. 调用事件
methods: {
addNum() {
this.$emit('add')
this.$emit('sub', 2) // 可以传参
}
}
// 3. 监听事件
`父组件`
<counter-operation @add="addA" @sub="aubA"/>
methods: {
addA() {
// 逻辑处理
},
aubA(value) {
console.log(value)
}
}
3. 非父子组件的通信(子孙组件)
// Provide和Inject 父组件提供,子孙组件使用
// 父组件有一个provide提供数据
// 子组件有个inject选项来开始使用这些数据
`父组件`
export default {
provide: {
name: '李晓'
}
// 当想使用data里的数据provide需要写成函数
provide() {
return {
name: this.name.length // 这里的数据不是响应式的,是一次性绑定
name: computed(() => this.name.length)
}
}
}
`子组件`
export default {
inject: ['name']
}
slot插槽
slot的使用过程就是,抽取共性,预留不同
vue中将 <slot> 元素作为承载分发内容的出口
缩写 #left v-lost可以写成#
// 组件
<template>
<div>
<h2>标题</h2>
<slot><i></i></slot> // 可以在slot里定义一个默认元素,没有使用时,就是默认元素
</div>
</template>
// 使用组件
<my-slot>
<button>这里的内容就会显示到插槽的位置</button>
</my-slot>
2. 具名插槽
<solt name="my-solt">
// 使用
<my-slot>
<template v-slot:my-solt> // 使用具名插槽
<button>这里的内容就会显示到插槽的位置</button>
<template>
</my-slot>
3. 动态插槽名称
通过v-slot: [dynamicSlotName] 方式动态绑定一个名称
<nav-bar>
<tempalte v-slot:[name]>
<button>
</button>
</tempalte>
</nav-bar>
data() {
return {
name: 'left'
}
}
3. 作用域插槽
<slot :item="item" :index="index"> // 传递子组件里的数据出去
// 接收
<template #="slotProps">
<template #:left="slotProps"> // 使用具名插槽
<button>{{slotProps.item}}</button>
<i>{{slotProps.index}}</i>
</template #="slotProps">
动态组件
动态组件是使用component组件,通过一个特殊的attribute is 来实现的
<component is="home"></component>
<!-- 动态绑定 -->
<component :is="currentTab"></component>
<!-- 可以向组件里传值,同过porps接收 -->
<component :is="currentTab"
name='coderwhy'
:age="18"
@pageClick="pageClick">
</component>
<script>
// home的值需要是通过component函数注册的组件或者是在组件内,通过components对象中注册的组件
data() {
return {
currentTab: 'home'
}
}
components: {
Home,
}
</script>
keep-alive 缓存组件
1. keep-alive 是 Vue的内置组件当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 transition 相似,keep-alive 是一个抽象组件:它自身不会渲染成一个 DOM 元素,也不会出现在父组件链中
2. 在组件切换过程中将状态保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性
<keep-alive>
<需要缓存的组件>
</keep-alive>
<!-- keep-alive的属性 当配置keep-alive属性时,要给组件添加name属性,再根据name进行匹配 -->
1. include -string| RegExp | Array 只有名称匹配的组件会被缓存
<keep-alive include='a,b'>
<需要缓存的组件>
</keep-alive>
<!-- 根据组件的name属性进行匹配 -->
<keep-alive :include="/a,b/">
<需要缓存的组件>
</keep-alive>
<keep-alive :include="['a','b']">
<需要缓存的组件>
</keep-alive>
2. exclude -string| RegExp | Array 任何名称匹配的组件都不会被缓存
3. max -number | string . 最多可以缓存多少组件实例,一旦达到这个数字,那么缓存组件中最近没有被访问的实例会被销毁
<!-- include 和exclude prop 允许组件有条件地缓存 -->
<!-- 二者都可以用逗号分隔字符串,正则表达式或者一个数组表达 -->
<!-- 匹配首先检查组件自身的name选项 -->
异步组件
当需要当前组件时才加载
import {defineAsyncComponent} from 'vue'
1. 函数写法 const AsyncAategory = defineAsyncComponent(() => import('./js/index.js'))
2. 对象写法
const AsyncCategory = defineAcyncCpomonent({
loader: () => import('./js/index.js')
loadingComponent: Loading,
delay: 2000 // 在显示loadingComponent 组件之前,等待多长时间
onError: function( err, ertry, attempts) {
// err 错误信息
// retry 函数,调用retry尝试重新加载
// attempts 记录尝试次数
}
})
$refs
1. 我们在组件中想要直接获取到元素对象或者子组件实例可以使用$refs属性
2. 组件实例有一个$refs属性,它是一个对象,持有注册过 ref attirbute的所有dom元素,和方法实例
<!-- 绑定 -->
<h2 ref="tempalteRef">
<!-- 使用 -->
methods: {
this.$refs.tempalteRef
}
$parent和$root
1.可以用过$parent来访问父元素
2.可以通过$root来访问根元素
console.log(this.$parent.message)
console.log(this.$root.message)
mixin
组件和组件之间有时候会存在相同的代码逻辑,我们可以对相同代码逻辑进行抽取
1. mixin提供了一种非常灵活的方式,来分发vue组件中的可复用功能
2. mixin对象可以包含任何组件选项
3. 当组件使用mixin对象时,所有mixin对象的选项将被混合进入该组件本身的选项中
mixin的合并规则
情况一:如果是data函数的返回值对象
1.返回值对象默认情况下会进行合并;
2.如果data返回值对象的属性发生了冲突,那么会保留组件自身的数据;情况二∶如何生命周期钩子函数
1.生命周期的钩子函数会被合并到数组中,都会被调用;情况三∶值为对象的选项,例如methods、components和 directives,将被合并为同一个对象。
1.比如都有methods选项,并且都定义了方法,那么它们都会生效;
2.但是如果对象的key相同,那么会取组件对象的键值对;
// ximin使用 js文件
export const demoMixin = {
data() {
return {
message: 'Hello Wrold'
}
},
methods: {
},
}
// 导入mixin文件
import {demoMixin} from './mixin.js'
export default {
mixins: [demoMixin], // demoMixin文件里的数据会混入本组件,成为本组件的一部分
data() {
}
}
vue3 CompositionAPI
setup() 的参数与返回值
setup有两个参数
1.props 父组件传递过来的属性会被放到props对象中,
2.context 有三个属性
attrs: 所有的非prop的attribute,
slots: 父组件传递过来的插槽
emit: 当我们组件内部需要发出事件时会用到emit
// setup返回值可以在template中被使用,也就是说我们可以通过setup的返回值来替代data选项
import { onMounted, onUpdated, onUnmounted } from 'vue'
export default {
setup(props, context) {
// 在 setup 中使用生命周期
onMounted(() => {
console.log('onMounted')
})
onUpdated(() => {
console.log('onUpdated')
})
onUnmounted(() => {
console.log('onUnmounted')
})
console.log(props.message)
console.log(context.attrs)
console.log(context.slots)
console.log(context.emit)
return {
title: 'Hello World'
}
}
}
Reactive
当我们使用reactive函数处理我们的数据之后,数据再次使用时会进行依赖收集
当数据发生改变时,所有收集到依赖都是进行对应的相应式操作,
对传入的类型是有限制的,必须是一个对象或者数组类型
import {reactive} from 'vue'
setup() {
const state = reactive({
name: 'coderwhy',
counter: 100
})
return {
state
}
}
Reactive 的判断 api
1.isproxy 检查对象是否由reactive或者readonly创建的proxy
2.isReactive 检查对象是否是由reactive创建的响应式代理
如果该代理是reactive建的,包裹了由reactive创建的另一个代理,它会返回true3.isReadonly 检查对象是否是由readonly创建的只读代理
4. toRaw 返回reactive或readonly代理的原始对象
5.shallowReactive 创建一个响应式代理,它之跟踪自身property的响应式,但不执行嵌套对象的深层响应式转换
6.shallowReadonly 创建一个proxy,使其自身的property为只读,但不执行嵌套对象的深层只读转换(深层还是可读可写的)
Ref
ref会返回一个可变的响应式对象,该对象作为一个响应式的引用维护了它内部的值,内部的值是在ref的value属性中被维护
在template模板中使用ref对象会自动解包,只能是浅层解包,
但是在setup函数内部,它依然是一个ref引用,要使用ref.value的方式
<button @click='increment'>{{state}}</button>
import {ref} from 'vue'
setup() {
let state = ref(100)
const increment = () => {
state.value++
console.log(state.value)
}
return {
state,
increment
}
}
// 拿元素ref属性
<h2 ref="title">
import { ref, watchEffect } from 'vue'
setup() {
const title = ref(null)
watchEffect(() => {
console.log(title.value)
})
return {
title
}
}
Ref的其他 api
toRefs
toRefs函数,可以将reactive返回的对象中的属性都转成ref
import {toRefs} from 'vue'
const state = reactive({
name:'why',
age:19
})
const {name, age } = toRefs(state)
// 相当于在state.name和ref.value之间建立了链接,任何一个修改都会引起另外一个变化
1. toRef // 只建立对象中的单个属性
import {toRef} from 'vue'
const state = reactive({
name:'why',
age:19
})
let name = toRef(state,'name')
unref
如果我们想要获取一个ref引用中的value,那么可以通过unref方法
如果参数是一个ref,则返回内部值,否则返回参数本身
这是 val = isRef(val) ? val.value: val 的语法糖函数
isRef
判断值是否是一个ref对象
shallowRef
创建一个浅层的ref对象
import {shallowRef} from 'vue'
setup() {
const info = shallowRef({name: 'why'})
return {
info
}
}
triggerRef
手动触发和shallowRef相关的副作用
import { ref, triggerRef } from 'vue'
setup() {
const info = ref({name: 'why'})
const changeInfo = () => {
info.value.name = 'james'
triggerRef(info)
}
return {
info
}
}
customRef
自定义ref,并对其依赖项跟踪和跟新触发,进行显示控制
需要一个工厂函数,该函数接受track 和 trigger 函数作为参数 并且应该返回一个带有get和set的对象
readonly
响应式对象不希望在别的地方修改,可以使用readonly
readonly 方法会传入三个类型的参数
1. 普通类型
2. reactive返回的对象
3. ref对象
import {readonly} from 'vue'
setup() {
const info = {
name: 'why'
}
const infoonly = readonly(info)
return {
infoonly
}
}
computed(计算属性)
// 计算属性
import { ref, computed } from 'vue'
setup() {
const firstName = ref('kobe')
const lastName = ref('Bryant')
// 函数写法
const fullName = computed(() => firstName.value+lastName.value)
// 对象写法
const fullName = computed({
get: ()=> firstName.value+lastName.value,
set: (value) => {}
})
return {
firstName,
lastName
}
}
watch 和 watchEffect
watchEffect
用于自动收集响应式数据的依赖
默认执行一次,只相应用到的依赖
import { ref, watchEffcect } from 'vue'
setup() {
const name = ref("why")
const age = ref(18)
watchEffect(() => { // 默认执行一次,只相应用到的依赖
console.log('name',name.value)
})
const stop = watchEffect(() => {
console.log('age': age.value)
})
const stop = watchEffect((aaa) => {
aaa(() => {
// 可以在这个函数中清除额外的副作用
request.cancel()
})
console.log('age': age.value)
})
const changeAge = () => {
age.value++
if(age.value>25){
stop() // 调用后,就不再侦听了
}
}
}
watch
1. watch 需要手动指定侦听的数据源,并在回调函数中执行副作用
2. 只有当被侦听的源发生变化时才会执行回调
3. 第一次不会直接执行
4. 访问侦听状态变化前后的值
import { reactive, watch } from 'vue'
// 侦听单个数据源
setup() {
const info = reactive({name: 'why', age: 18})
`1. 侦听watch时,传入一个getter函数`
watch(() => info.name, (newValue, oldValue) => {
consloe.log('新:'newVlaue "旧"oldValue)
})
`2. 传入可响应对象,reactive对象/ref对象`
'情况一: reactive对象获取到的newvalue和oldvalue本身都是reactive对象'
watch(info,(newValue, oldValue) => {
consloe.log('新:'newVlaue "旧"oldValue)
})
'情况二: ref对象获取newvalue和oldvalue是value值本省'
const name = ref('why')
watch(name,(newValue, oldValue) => {
consloe.log('新:'newVlaue "旧"oldValue)
})
'如果希望newvalue和oldvalue是一个普通对象'
watch(()=> {
return {...info}
},(newValue, oldValue) => {
consloe.log('新:'newVlaue "旧"oldValue)
})
return {
}
}
// 侦听多个数据源
setup() {
const info = reactive({name: 'why',age: 18})
const name = ref('why')
watch([info,name],([newValue, oldValue],[newValue, oldValue])=> {
consloe.log('新:'newVlaue "旧"oldValue)
},{
deep: true // 深度监听,直接监听reactive对象时是默认就是为true
immediate: true // 默认执行一次
})
return {
}
}
provide inject
无论组件层次结构有多深,父组件都可以作为其所有子组件的依赖提供者。这个特性有两个部分:父组件有一个
provide
选项来提供数据,子组件有一个inject
选项来开始使用这些数据。
// 给子孙组件传值
<home/>
import {provide } from 'vue'
import Home from './Home.vue'
setup(){
const name = 'whty'
provide('name',name)
}
// 子孙组件
import {inject} from 'vue'
setup() {
const name = inject('name','提供默认值')
return {
name
}
}
render 函数(渲染函数)
export default {
render() {
return h() // h() 函数是用于创建vnode的一个函数
return h() // 接收三个参数
1.{string|object|function} 一个html标签,一个组件,一个异步组件或者一个函数式组件
'div' // 必须的
2. {object} props 与attribute,prop 事件相应的对象,我们会在模板中使用
{} // 可选的
3. {string|array|object|children} 子vnodes 使用`h()`构建,或者字符串获取文本vnode或者有插槽的对象
['some text comes first', h('h1', 'A headline'), h(MyComponent, {someProp: 'foobar'})]
}
}
// 例子
import { h } from 'vue'
export default {
render() {
return h('div', {class: 'app'}, [
h('h2', null, `当前计数: ${this.counter}`),
h('button', {
onClick: () => this.counter++
}, '+1')
h('button', {
onClick: () => this.counter--
}, '-1')
])
}
}
自定义指令
1、指令的生命周期
created: 在绑定元素attribute或者事件监听器被应用之前调用
beforMount: 当指令第一次绑定到元素并且在挂载父组件之前调用
mounted:在绑定元素的父组件被挂载后调用;
beforeUpdate :在更新包含组件的 VNode之前调用;
updated:在包含组件的VNode 及其子组件的VNode更新后调用;beforeUnmount:在卸载绑定元素的父组件之前调用;
unmounted:当指令与元素解除绑定且父组件已卸载时,只调用一次;
// 在某些情况下,你需要对DOM进行底层操作时,就会用到自定义指令
direactives: {
focus: {
mounted(el, bindings, vnode ,preVnode) {
console.log('focus mounted')
el.focus()
}
}
}
nexttick
将回调推迟到下一个dom更新周期之后执行,在更改一些数据等待dom更新后立即使用它
import {nextTick} from 'vue'
setup() {
nexttick(() => {
// 更新dom后操作
})
}
router 配置
const routes = [
{
path: '/',
redirect: '/home' // 重定向
},
{
path: '/home',
name: 'home', // 路由唯一的名字
// 魔法注释,分包操作
components: () => import(/* webpackChunName: 'home-chunk'*/'./home'), // 路由懒加载
meta: { name: 'why', age: 18 } // 原数据
quilren:[
{
path: 'message' // 嵌套路由
}
]
},
{
path: '/why/:name' // 动态路由 $route.params.name可以拿动态路由的值
`vue3` import { useRoute } from 'vue-router'
setup() {
const route = useRoute()
route.params.name
}
},
{
path: '/:pathMatch(.*)' // 任意匹配
component: () => import('./NotFound.vue')
}
]
`编程式导航`
this.$router.push()
this.$router.push({path:'',query:{}})
this.$router.push({name:'',params: {}})
import { useRouter } from 'vue-router'
setup() {
const router = useRouter()
const click = () => {
router.push('/')
}
return {
click
}
}
动态添加路由
`动态添加路由`
const caregoryRoute = {
path: '/category',
component: () => import('./')
}
// 添加顶级路由对象
router.addRoute(caregoryRoute)
// 添加二级路由对象
router.addRoute('home', {
path: 'moment',
component: () => import('')
})
`动态删除路由`
1.添加一个name相同的路由
route.addRoute({path:'/a',name: 'a'})
route.addRoute({path:'/b',name: 'a'})
2.通过removeRoute方法,传入路由名称
route.removeRoute('/a')
3.通过addRoute方法的返回值回调
const removeRoute = route.addRoute(reoteRecord)
removeRoute()
router.hasRoute() // 查询路由是否存在
router.getRoutes() // 获取一个包含所有路由记录的数组
路由导航守卫
`前置导航守卫`
router.beforEach((to,from,`next`) => {
// next vue-router4已经不使用了
// to 即将跳转到的route对象
// from 从那个route对象来的
// 进行了一次路由跳转
return false
// 返回值问题
1. false 不进行导航
2. undefined 或者不写返回值,进行默认导航
3. 字符串 '/login'
4. 对象: 类似于 router.push({path: '',query: {}})
})
`后置导航守卫`
router.afterEach((to,home) => {
// 在路由跳转之后,再回调
})
vuex
vuex应用的核心就是store(仓库)
vuex的状态存储是响应式的
不能在组件内直接修改store中的状态,需要提交(commit)mutation
import { createStore } from 'vuex'
const store = createStore({
namespaced: true // 使用modules开启命名空间
state() { // 数据管理
return {
counte: 1
}
},
// 某些属性我们需要经过变化后使用,可以使用getters
getters: {
current(state,getters) {
// 参数一 state对象
// 参数二 getters 对象
return function(n) { // 返回函数写法
return 3
}
}
} `使用$store.getters.方法名`
// 更改vuex的store中的状态的唯一方法就是提交mutation
mutations: {
increment(state,paload) {
// 参数一state对象
// 参数二调用传递的参数
}
`使用$store.commit('increment', {name: '男'})`
}
// actions 可以包含任意异步操作, 提交的是mutarion 而不是直接变更状态
actions: {
getHomeMultiDate(context,payload) {
context.commite('addBannerData',{age:18})
}
`使用this.$store.dispatch('getHomeMultiDate',{name: 'age'})`
}
// 讲store分割成模块
import { a, b } from './a'
modules: {
a: moduleA,
b: moduleB
`使用$store.state.a`
}
})
export default store
`vue2组件中使用`
import { mapState, mapGetters, mapMtations, mapActions } from 'vuex'
methods: {
...mapMutations(['increment'],{name: '男'})
...mapActions(['getHomeMultiDate'])
},
computed: {
fullName() {
return this.$store.state.counte
}
// 数组写法
...mapState(['counte'])
...mapGetters(['current'])
// 对象写法
...mapState({
Scounte: state => state.counte
})
...mapGetters({
current: 'current'
})
}
`vue3中使用`
import { mapState, useStore, mapGetters,mapMtations, mapActions } from 'vuex'
import { computed } from 'vue'
setup() {
// 第一种方式
const store = useStore() // 拿到store对象
const sCounter = computed(() => store.state.counter)
// 第二种方式(可以封装)
const storeStateFns = mapState(['age', 'name'])
// 同理
const storemapGettersFns = mapGetters(['age', 'name'])
const storeState = {}
Object.keys(storeStateFns).forEach(fnKey => {
const fn = storeState[fnKey].bind({$store: store}) // 绑定this
storeState[fnKey] = computed(fn)
})
const storeMutations = mapMtations(['increment'])
const storeMapActions = mapActions(['increment'])
return {
sCounter
...storeState
...storeMutations
...storeMapActions
}
}
vue3 注册全局实例属性或方法,在 setup 中使用
const app = createApp({})
app.config.globalProperties.$axios = () => {}
// setup中使用
import { getCurrentInstance } from 'vue'
;`getCurrentInstance这个函数来返回当前组件的实例对象,也就是当前vue这个实例对象`
//vue3的setup函数中的this为undefined,需要使用组合API提供的getCurrentInstance()函数,通过appContext.config.globalProperties来调用根实例上挂载的方法。
// tips:另外如果想获取当前组件实例,通过getCurrentInstance下的proxy实现,proxy支持开发环境、生产环境,而ctx只支持开发环境,打包后结构不一样
const instance = getCurrentInstance()
console.log(instance.appContext.config.globalProperties) // 打印可以看到当前组件上挂载了的方法
instance.appContext.config.globalProperties.$axios() // 使用axios