-----------------------------------------------------------------------------
vue3性能更高 体积更小 更利于复用 代码维护方便(compositionAPI)
新特性
1. 数据响应式原理重新实现 (ES6 proxy 替代了 ES5 的 Object.defineProperty)
解决了: 例如数组的更新检测等bug, 大大优化了响应式监听的性能
(原来检测对象属性的变化, 需要一个个对属性递归监听) proxy 可以直接对整个对象劫持
2.虚拟DOM - 新算法 (更快 更小)
3.组合api(compositionAPI)
4.多个根组件
5.源码用 typescript 重写, 有更好的类型推导 (类型检测更为严格, 更稳定)
antdesign常用于react 但是也有vue的版本
vue2中
optionsAPI项目大了难以维护 methods computed 会依赖data中的数据 当使用了该data的功能需要修改的时候 需要拉滚动条去找到对应模块逐个修改data methods computed
vue3中
compositionAPI 组合API
vite(支持vue3 react 不支持vue2 )
新的构建工具vite
用ESM 无需打包
轻量快速的热重载 模块热重载
丰富的功能 ts jsx css
等等
创建vue3项目
yarn create vite
输入项目名字 不要中文
创建项目简单写法
创建vue3项目
yarn create vite 01-demo --template vue
创建vue3-ts项目
yarn create vite 01-demo --template vue-ts
语法检测插件 标签高亮
vetur(vue2)和volar(vue3)不能同时装
optionsAPI
优点:简单易学 易于使用
缺点:项目大了 逻辑不容易复用
可以复用使用mixins方法(混入)
compositionAPI
更容易维护 提高代码可读性
要用compositionAPI就要写setup
setup函数 compositionAPI的起点
在beforeCreate之前执行
setup中不能用this this指向undefined
模板中使用数据和结构需要在setup返回(return)
其他钩子函数this指的是当前组件实例
reactive函数
要传入一个复杂类型数据 不能传入简单数据类型
将一个复杂类型数据 变成响应式数据
import { reactive } from 'vue'
const mouse = reactive({
x: 0,
y: 0
})
const move = e => {
mouse.x = e.pageX
mouse.y = e.pageY
}
document.addEventListener('mousemove', move)
return {
mouse,
move,
}
使用reactive函数之后才可以变成响应式数据
ref函数 将简单数据类型转为响应式数据
ref会返回一个对象 对象有一个值value
ref(100) 会返回一个 {value:100}
而且在模板中这个值会自动解套 不用额外的.value就可以访问
let money= ref(100)
js中访问需要money.value
ref也支持传复杂的类型 转为响应式数据
ref可以用于简单数据类型和复杂数据类型
从vue3.2.0之后更推荐使用ref 性能更好了
SFC单文件组件
script setup vue3中的新语法
在script中写setup 就不用写
export default{
setup(){
return {}
}
}
下面两段script可以同时写
<script>
export default {
name:''
}
</script>
<script setup>
import {ref} from 'vue'
let user = ref({
name:'zs',
age:18
})
</script>
顶层的绑定会自动暴露给模板,所以定义的变量,函数和import导入的内容都可以直接在模板中直接使用
顶层的变量里面的变量不可以直接在模板中直接使用
computed也有缓存
也有get set
要接收计算属性的返回值
const age = ref(18)
两种写法 第一种写回调函数只能读
const nextAge = computed(() => {
console.log('我打印了')
return +age.value + 1
})
第二种写法写对象 写get set
const nextAge2 = computed({
get() {
return +age.value + 2
},
set(value) {
age.value = value - 2
}
})
侦听器
可以侦听ref reactive响应式数据的变化
import { ref, watch } from 'vue'
const money = ref(100)
const car = ref('小黄车')
const add = () => {
money.value++
}
money 和 car 可以分开侦听 也可以写到数组里一起侦听
watch三个参数
第一个:要侦听的数据
第二个:回调函数,有两个参数 newV oldV
第三个:是否开启 深度监听 和 立即执行
watch(
[money, car],
(value, oldValue) => {
console.log(value, oldValue)
},
{
deep: true,
immediate: true
}
)
侦听复杂类型要加deep:true
watch(
user,
value => {
console.log(value)
},
{
deep: true
}
)
侦听复杂类型的某一个值
const user = ref({
name: 'zs',
age: 18
})
watch(
() => user.value.name,
value => {
console.log('值变化了', value)
}
)
eventbus在vue3中没有了
在vue3中导入组件就能用了 不用注册了
父传子
父组件给子组件传值
子组件使用defineProps接收数据
const props = defineProps({
money: Number,
car: String
})
console.log(props)
要想接收的数据在js中也可以用 需要定义一个props接收
子传父
子组件
const props = defineProps({
money: Number,
car: String
})
const emit = defineEmits(['minus'])
const minus = () => {
emit('minus', 500)
}
父组件
<Son :money="money" :car="car" @minus="minus"></Son>
const minus = m => {
money.value = money.value - m
}
provide 和 inject
跨层级的简单组件通信 所有后代组件 例如父子 爷孙
复杂的还是用vuex vue3中是pinia
父组件
let money = ref(1000)
let car = ref('宏光mini')
const changeMoney = m => {
money.value = money.value - m
}
provide('money', money)
provide('car', car)
provide('changeMoney', changeMoney)
孙组件
const money = inject('money')
const car = inject('car')
const changeMoney = inject('changeMoney')
<h5>孙组件-----{{ money }}-----{{ car }}</h5>
<button @click="changeMoney(10)">-10</button>
ref也可以操作dom 也可以操作组件 调用组件的方法
import { ref } from 'vue'
const h1Ref = ref(null)
const change = () => {
// h1Ref.value就可以操作dom元素 再.innerHTML还可以修改元素
console.log(h1Ref.value)
}
<h1 ref="h1Ref">根组件</h1>
<button @click="change">修改</button>
ref操作组件
将组件的通用方法和属性通过defineExopse暴露出去
通过ref默认是访问不到获取到的组件的属性和方法的
需要被访问的组件 script setup 中 defineExopse的暴露几个属性 方法,外面就能用几个属性 方法
父组件
import { ref } from 'vue'
import Form from './components/Form.vue'
const h1Ref = ref(null)
// 这里定义子组件的ref
const formRef = ref(null)
const fn = () => {
console.log(h1Ref.value)
// 这里使用子组件的方法
console.log(formRef.value)
formRef.value.validate()
}
<div>根组件</div>
<h1 ref="h1Ref">根组件</h1>
<button @click="fn">修改</button>
<hr />
<Form ref="formRef"></Form>
子组件
import { ref } from 'vue'
const count = ref(0)
const validate = () => {
console.log('表单校验方法')
}
// 暴露属性给外部组件使用
defineExpose({
count,
validate,
})
vue3废弃了过滤器 过滤器本质就是个函数
如果对一个响应式对象进行解构 解构出来的数据会丢失响应式能力 有响应式的是那个对象
通过toRefs和toRef可以保留响应式能力
错误案例:
import { reactive, ref } from 'vue'
const user = reactive({
name: 'zs',
age: 18
})
const { name, age } = user
<div>{{ name }}------{{ age }}</div>
<input type="text" v-model="name" />
<input type="text" v-model="age" />
正确案例如下:
const { name, age } = toRefs(user)
或者
const name = toRef(user, 'name')
const age = toRef(user, 'age')
或者
const user = ref({
name: 'zs',
age: 18
})
const { name, age } = toRefs(user.value)
下面两行是一样的 只是写了delTodo的话 会在下面的第四行有提示
const emit = defineEmits()
const emit = defineEmits('delTodo')
emit('delTodo',id)
vue3的钩子函数
beforeCreate 和 created没了 变成了 setup
beforeMount 变成了 onBeforeMount
mounted 变成了 onMounted
beforeUpdate 变成了 onBeforeUpdate
updated 变成了 onUpdated
beforeUnmount(beforeDestroy) 变成了 onBeforeUnmount
unmounted(destroyed) 变成了 onUnmounted
-----------------------------------------------------------------------------
vue2全家桶 vue2配合路由3和vuex3
vue@2 + vue-router@3 + vuex@3 optionsAPI
vue3全家桶 vue3配合路由4和vuex4 compositionAPI
vue@3 + vue-router@4 + vuex@4(pinia 比 vuex4更好)
router4
yarn add vue-router
新建文件夹router/index.js
const router = createRouter({
// vue3中必须要写
history: createWebHashHistory(),
routes:[]
})
export default router
main.js中
import router from '路径'
app.use(router)
.vue中使用
路由信息对象
const route = useRoute()
路由实例对象
const router = useRouter()
vuex4在vue3中能用 但是不好用
vuex4可以和pinia一起用但是不建议这么做
pinia没有模块的概念了 它可以有任意多的store(例如在store创建car.js money.js)
参数一:模块名
参数二:对象 用于pinia的核心概念 state actions getters 没有mutations
state中也要写成函数的形式() => {} 不要写成对象{},防止变量污染
defineStore返回的是一个函数 在外面调用的话还要加一个() 例如:useCountStore()
import { defineStore } from 'pinia'
const useCountStore = defineStore('', {
state: () => {
return {
count: 0
}
}
})
exportdefault useCounterStore
import {storeToRefs} from 'pinia'
const { count, double, money } = storeToRefs(counter)
可以解构pinia中的state和getters中的值
pinia模块化思想
在store下建一个modules文件夹 同级建一个index.js js都写到modules中 最后全部导入到index.js中
这里的todos是一个module
侦听 pinia中的数组变化
todos.$subscribe(()=>{
})