# vue 技术
Vue3 基础知识点
# 生命周期
Vue2.x | Vue3 |
---|---|
beforeCreate | Not needed* |
created | Not needed* |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestroy | onBeforeUnmount |
destroyed | onUnmounted |
activated | onActivated |
deactivated | onDeactivated |
errorCaptured | onErrorCaptured |
Tips: setup 是围绕 beforeCreate 和 created 生命周期钩子运行的,所以不需要显式地去定义。
# watchEffect 的使用
import {
ref,
watchEffect,
} from 'vue'
let sum = ref(0)
watchEffect(()=>{
const x1 = sum.value
console.log('watchEffect所指定的回调执行了')
})
# watch 的使用
import {
reactive,
watch,
} from 'vue'
//数据
let sum = ref(0)
let msg = ref('你好啊')
let person = reactive({
name:'张三',
age:18,
job:{
j1:{
salary:20
}
}
})
// 两种监听格式
watch([sum,msg],(newValue,oldValue)=>{
console.log('sum或msg变了',newValue,oldValue)
},{immediate:true})
watch(()=>person.job,(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{deep:true})
# computed 计算属性的使用
import {
reactive,
computed,
} from 'vue'
//数据
let person = reactive({
firstName:'小',
lastName:'叮当'
})
// 计算属性简写
person.fullName = computed(()=>{
return person.firstName + '-' + person.lastName
})
// 完整写法
person.fullName = computed({
get(){
return person.firstName + '-' + person.lastName
},
set(value){
const nameArr = value.split('-')
person.firstName = nameArr[0]
person.lastName = nameArr[1]
}
})
# props 父子传值的使用
父组件代码如下(示例)
<template>
<child :name='name'/>
</template>
<script setup>
import {ref} from 'vue'
// 引入子组件
import child from './child.vue'
let name= ref('小叮当')
</script>
2
3
4
5
6
7
8
9
10
子组件代码如下(示例)
<template>
<span>{{props.name}}</span>
</template>
<script setup>
import { defineProps } from 'vue'
// 声明props
const props = defineProps({
name: {
type: String,
default: '11'
}
})
// 或者
//const props = defineProps(['name'])
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# emit 子父传值的使用
父组件代码如下(示例)
<template>
<AdoutExe @aboutExeVisible="aboutExeHandleCancel" />
</template>
<script setup>
import {reactive} from 'vue'
// 导入子组件
import AdoutExe from '../components/AdoutExeCom'
const data = reactive({
aboutExeVisible: false,
})
// content组件ref
// 关于系统隐藏
const aboutExeHandleCancel = () => {
data.aboutExeVisible = false
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
子组件代码如下(示例)
<template>
<a-button @click="isOk">
确定
</a-button>
</template>
<script setup>
import { defineEmits } from 'vue';
// emit
const emit = defineEmits(['aboutExeVisible'])
/**
* 方法
*/
// 点击确定按钮
const isOk = () => {
emit('aboutExeVisible');
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 获取子组件 ref 变量和 defineExpose 暴露
父组件代码如下(示例)
<template>
<button @click="onClickSetUp">点击</button>
<Content ref="content" />
</template>
<script setup>
import {ref} from 'vue'
// content组件ref
const content = ref('content')
// 点击设置
const onClickSetUp = ({ key }) => {
content.value.modelVisible = true
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
子组件代码如下(示例)
<template>
<p>{{data }}</p>
</template>
<script setup>
import {
reactive,
toRefs
} from 'vue'
/**
* 数据部分
* */
const data = reactive({
modelVisible: false
})
defineExpose({
...toRefs(data),
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 路由 useRoute 和 useRouter 的使用
<script setup>
import { useRoute, useRouter } from 'vue-router'
// 声明
const route = useRoute()
const router = useRouter()
// 获取query
console.log(route.query)
// 获取params
console.log(route.params)
// 路由跳转
router.push({
path: `/index`
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# store 仓库的使用
import { useStore } from 'vuex'
import { num } from '../store/index'
const store = useStore(num)
// 获取Vuex的state
console.log(store.state.number)
// 获取Vuex的getters
console.log(store.state.getNumber)
// 提交mutations
store.commit('fnName')
// 分发actions的方法
store.dispatch('fnName')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# provide 和 inject 祖孙传值
父组件代码如下(示例)
<template>
<AdoutExe />
</template>
<script setup>
import { ref,provide } from 'vue'
import AdoutExe from '@/components/AdoutExeCom'
let name = ref('Jerry')
// 使用provide
provide('provideState', {
name,
changeName: () => {
name.value = '小叮当'
}
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
子组件代码如下(示例)
import { inject } from 'vue'
const provideState = inject('provideState')
provideState.changeName()
2
3
4
# 自定义 v-model
要使自定义的 Vue 组件支持 v-model,需要实现一个名为 value 的 prop 和一个名为 input 的事件。在组件内 部,将 value prop 绑定到组件的内部状态,然后在对内部状态进行修改时触发 input 事件。
下面是一个简单的例子,展示如何创建一个自定义的输入框组件并支持 v-model
<template>
<input :value="value" @input="$emit('input', $event.target.value)" />
</template>
<script>
export default {
name: 'MyInput',
props: {
value: String
}
};
</script>
2
3
4
5
6
7
8
9
10
11
12
在上面的组件中,我们定义了一个 value prop,这是与 v-model 绑定的数据。我们还将内置的 input 事件转发 为一个自定义的 input 事件,并在事件处理程序中更新内部状态。
现在,我们可以在父组件中使用 v-model 来绑定这个自定义组件的值,就像使用普通的输入框一样
<template>
<div>
<my-input v-model="message" />
<p>{{ message }}</p>
</div>
</template>
<script>
import MyInput from './MyInput.vue';
export default {
components: {
MyInput
},
data() {
return {
message: ''
};
}
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
在上面的代码中,我们通过使用 v-model 指令来双向绑定 message 数据和 MyInput 组件的值。当用户在输入框 中输入文本时,MyInput 组件会触发 input 事件,并将其更新的值发送给父组件,从而实现了双向绑定的效果。
# 事件总线(EventBus)
Vue 事件总线是一个事件处理机制,它可以让组件之间进行通信,以便在应用程序中共享信息。在 Vue.js 应用程 序中,事件总线通常是一个全局实例,可以用来发送和接收事件。
以下是使用 Vue 事件总线的步骤:
3.1 创建一个全局 Vue 实例作为事件总线
import Vue from 'vue'
export const eventBus = new Vue()
2
3.2 在需要发送事件的组件中,使用$emit 方法触发事件并传递数据
eventBus.$emit('eventName', data)
在需要接收事件的组件中,使用$on 方法监听事件并处理数据
eventBus.$on('eventName', data => {
// 处理数据
})
2
3
需要注意的是,事件总线是全局的,所以在不同的组件中,需要保证事件名称的唯一性。另外,需要在组件销毁前 使用$off 方法取消事件监听
eventBus.$off('eventName')
这样就可以在 Vue.js 应用程序中使用事件总线来实现组件之间的通信了。
# 渲染组件 render 方法
Vue 的 render 方法是用来渲染组件的函数,它可以用来替代模板语法,通过代码的方式来生成 DOM 结构。相较 于模板语法,render 方法具有更好的类型检查和代码提示。
下面详细介绍 Vue 的 render 方法的使用方法:
4.1 基本语法
render 方法的基本语法如下
render: function (createElement) {
// 返回一个 VNode
}
2
3
其中 createElement 是一个函数,它用来创建 VNode(虚拟节点),并返回一个 VNode 对象。
4.2 创建 VNode
要创建 VNode,可以调用 createElement 函数,该函数接受三个参数:
标签名或组件名
可选的属性对象
子节点数组
例如,下面的代码创建了一个包含文本节点的 div 元素
render: function (createElement) {
return createElement('div', 'Hello, world!')
}
2
3
如果要创建一个带有子节点的元素,可以将子节点作为第三个参数传递给 createElement 函数。
例如,下面的代码创建了一个包含两个子元素的 div 元素
render: function (createElement) {
return createElement('div', [
createElement('h1', 'Hello'),
createElement('p', 'World')
])
}
2
3
4
5
6
如果要给元素添加属性,可以将属性对象作为第二个参数传递给 createElement 函数。
例如,下面的代码创建了一个带有样式和事件处理程序的 button 元素
render: function (createElement) {
return createElement('button', {
style: { backgroundColor: 'red' },
on: {
click: this.handleClick
}
}, 'Click me')
},
methods: {
handleClick: function () {
console.log('Button clicked')
}
}
2
3
4
5
6
7
8
9
10
11
12
13
4.3 动态数据
render 方法可以根据组件的状态动态生成内容。要在 render 方法中使用组件的数据,可以使用 this 关键字来 访问组件实例的属性。
例如,下面的代码根据组件的状态动态生成了一个带有计数器的 div 元素
render: function (createElement) {
return createElement('div', [
createElement('p', 'Count: ' + this.count),
createElement('button', {
on: {
click: this.increment
}
}, 'Increment')
])
},
data: function () {
return {
count: 0
}
},
methods: {
increment: function () {
this.count++
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
4.4 JSX
在使用 Vue 的 render 方法时,也可以使用 JSX(JavaScript XML)语法,这样可以更方便地编写模板。要使用 JSX,需要在组件中导入 Vue 和 createElement 函数,并在 render 方法中使用 JSX 语法。
例如,下面的代码使用了 JSX 语法来创建一个计数器组件
import Vue from 'vue'
export default {
render() {
return (
<div>
<p>Count:{this.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
)
},
data() {
return { count: 0 }
},
methods: {
increment() {
this.count++
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
注意,在使用 JSX 时,需要使用 {} 包裹 JavaScript 表达式。
4.5 生成函数式组件
除了生成普通的组件,render 方法还可以生成函数式组件。函数式组件没有状态,只接收 props 作为输入,并返 回一个 VNode。因为函数式组件没有状态,所以它们的性能比普通组件更高。
要生成函数式组件,可以在组件定义中将 functional 属性设置为 true。
例如,下面的代码定义了一个函数式组件,用于显示列表项
export default {
functional: true,
props: ['item'],
render: function (createElement, context) {
return createElement('li', context.props.item)
}
}
2
3
4
5
6
7
注意,在函数式组件中,props 作为第二个参数传递给 render 方法。