Vue3基础
使用脚手架搭建需要确保@vue/cli 版本在 4.5.0 以上 查看@vue/cli 版本 vue --version
如果 vue/cli 版本过低或上方命令报错,需要安装或者升级你的 @vue/cli npm install -g @vue/cli
生命周期
vue2 --------> vue3 beforeCreate --------> setup(()=>{}) created --------> setup(()=>{}) beforeMount --------> onBeforeMount(()=>{}) mounted --------> onMounted(()=>{}) beforeUpdate --------> onBeforeUpdate(()=>{}) updated --------> onUpdated(()=>{}) beforeDestroy --------> onBeforeUnmount(()=>{}) destroyed --------> onUnmounted(()=>{}) activated --------> onActivated(()=>{}) deactivated --------> onDeactivated(()=>{}) errorCaptured --------> onErrorCaptured(()=>{})
setup()
Composition API 将 vue 中的很多功能拆分成了一个一个的 hook
可以理解为 Vue3 中一个新的配置项,值为一个函数 setup()
setup()
是所有 Composition API(组合式 API)的入口
在 setup()
函数内的 this
指向 undefined
setup 函数是处于生命周期函数 beforeCreate
和 Created
两个钩子函数之前的函数,也就说在 setup 函数中是无法使用 data
和 methods
中的数据和方法的
在 setup 函数中定义的变量和方法最后都是需要 return
出去的,不然无法在模板中使用
注意:如果 data
内的变量和 setup
函数内的变量重名,优先使用 setup
里面的变量
setup 可以接受参数 props
和 content
setup(props, content){} # or setup(props, { attrs, slots, emit }) {}
props
组件外部传递进入或组件内部声明已经接收的属性
// 父组件 <son :name = "obj.name"></son> // 子组件 <template> <div> <h1>我是子组件</h1> <div>{{ name }}</div> </div> </template> <script> export default { props: { name: { type: String } }, setup(props, context) { console.log(props) } } </script>
context
包含 attrs
,slots
和 emit
,content
参数可以解构
attrs
是组件外部传递进入组件的值,但组件内部未在 props
内声明,即可使用 context.attrs
得到
// 父组件 <son :name = "obj.name" :age = "obj.age"></son> // 子组件 <script> export default { props: { name: { type: String } }, setup(props, context) { console.log(props) console.log(context.attrs.age)// 此时未在props声明age } </script>
emit
用于分发自定义函数,等同于 this.$emit
,可用于子向父传值
// 子组件 <button @click = "son">子组件</button> <script> export default { setup(props, context) { const son = () => { context.emit('change', 50) } return { son } } } </script> // 父组件 <template> <div> <h1>我是父组件</h1> <div>子组件可以改变我的值{{ sonval }}</div> <div>---------------------------------------</div> <son :name = "obj.name" :age = "obj.age" @change = "formSon"></son> </div> </template> <script> import son from '../components/son.vue' import { ref } from 'vue' export default { name: 'Father', components: { son }, setup() { let sonval = ref(0) const formSon = val => { sonval.value = val } return { formSon, sonval } } } </script>
slots
可以获取插槽的内容,相当于 this.$slots
// 子组件 <template> <div> <h1>我是子组件</h1> <slot name="son"> <div>默认插槽</div> </slot> </div> </template> <script> export default { props: { name: { type: String } }, setup(props, context) { console.log(context.slots.son()[0])// 获取slot的信息 } } </script> // 父组件 <son> <template v-slot:son> <p>我是父组件呵呵哈哈哈</p> </template> </son>
setup 语法糖
vue3.2 开始,在 script 脚本上声明 setup 会自动将所有顶级函数和变量自动暴露给模板使用
<template> <div> {{ name }} <button @click = "changeName">改变名字</button> </div> </template> <script setup> import { ref } from 'vue' const name = ref('user') const changeName = () => { name.value = 'newUser' } </script>
因为没有了 setup 函数,如果需要使用 props
,emit
,attrs
等参数,需要调用相关函数
defineProps
用来接收父组件传来的 props
defineEmits
用来声明触发的事件
useAttrs
用来接收父组件传递但子组件未使用 props
接收的变量
useSlots
用来获取插槽相关信息
const emit = defineEmits(['change']) const props = defineProps(['age']) const slots = useSlots() const attrs = useAttrs()
数据定义
ref
使用 ref 可以定义一个响应式数据 const xxx=ref(initValue)
使用前需要按需导入,ref 定义的响应式数据修改数据时必需要.value
取值
<script setup> import { ref } from 'vue' // 括号内的为初始值 // 基本数据类型 number,string,boolean let name=ref('张三'); let age=ref(18); let isMarry=ref(false); // 使用ref定义数组 let hobby=ref(['吃饭','睡觉','打豆豆']); // 使用ref定义对象 let user=ref({ idCard:'身份证', nation:['中国','美国','英国','俄罗斯'] }) const changeName = () => { name.value = '李四'// name.value修改数据 } </script>
reactive 函数
使用 reactive
可以定义一个响应式数据 const 代理对象=reactive(被代理的对象)
接收一个对象(或数组),返回一个代理器对象(Proxy 的实例对象,简称 Proxy 对象)
使用前需要按需导入reactive
<script setup> import { reactive } from 'vue' let student=reactive({ name:'张三', age:19, hobbies:['吃饭','睡觉','打豆豆'] }); console.log(student) const changeName = () => { student.name = '李四' // 直接修改数据 } </script>
reactive 与 ref
ref
多用来定义:基本类型数据
reactive
多用来定义:对象(或数组)类型数据
注意:ref 也可以用来定义对象(或数组)类型的数据,它内部会自动通过 reactive 转为代理对象
两者原理
ref
通过 Object.defineProperty()
的 get 和 set 实现(响应式)数据劫持
reactive
通过使用 Proxy
来实现响应式(数据劫持),并通过 Reflect 操作源对象内部的数据 从使用角度
所以 ref
操作数据需要.value
,但 reactive
定义的数据可以直接修改
toRef、toRefs
使用 toRef 创建一个 ref 对象,其 value 值指向另一个对象中的某个属性值
<template> <h2>姓名:{{name}}</h2> <h2>年龄:{{age}}</h2> </template> <script> import {reactive,toRef} from 'vue' export default { setup(){ let person=reactive({ name:'user', age:18 }) return{ name: toRef(person, 'name'), age: toRef(person, 'age'), } } } </script>
toRefs 与 toRef 功能一致,但可以批量创建多个 ref 对象
<template> <h2>姓名:{{name}}</h2> <h2>年龄:{{age}}</h2> </template> <script> import {reactive,toRef} from 'vue' export default { setup(){ let person=reactive({ name:'user', age:18 }) return{ ...toRefs(person) } } } </script>
数据处理
shallowRef 和 shallowReactive
shallowReactive
:只处理对象最外层属性的响应式(浅响应式),对深层次的数据不会改变视图但会改变数据
const state = shallowReactive({ foo: 1, nested: { bar: 2 } }) // 改变 state 本身的性质是响应式的 state.foo++ // ...但是不转换嵌套对象 isReactive(state.nested) // false state.nested.bar++ // 非响应式
如果有一个对象数据,结构比较深,但变化时只是外层属性变化用 shallowReactive
shallowRef
: 只处理基本数据类型的响应式,不进行对象的响应式处理
const a = shallowRef({ b: 1 }) a.value.b = 2 //视图不会更新 console.log(a.value) //{b : 2} 但是能追踪到值得变化 a.value = { b: 2 } //一整个替换时,视图会变化
如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换用 shallowRef
readonly 和 shallowReadonly
readonly
:让一个响应式数据变为只读的(深只读),所有的数据将无法被修改
shallowReadonly
:让一个响应式变为只读的(浅只读),基本数据类型无法被修改,对象可以被修改
<template> <div>{{ sum }}</div> <button @click = "sum++">sum按钮</button> <div>{{ name }}</div> <button @click = "name += '~'">按钮name</button> <div>{{ job.j1.salary }}</div> <button @click = "job.j1.salary++">按钮salary</button> </template> <script> import { reactive, ref, toRefs, shallowReadonly } from 'vue' export default { name: 'DemoComponent', setup() { let sum = ref(0); let person = reactive({ name: '张三', job: { j1: { salary: 20 } } }) // 深只读,对象层次深也能检测不能改变数据 person = readonly(person); // 浅只读,只能控制第一层 person = shallowReadonly(person); return { sum, ...toRefs(person), } } } </script>
toRaw 和 markRaw
toRaw
将一个由 reactive
生成的响应式对象转为普通对象对这个普通对象的所有操作,不会引起页面更新,对 ref 定义的响应式数据无效!
markRow
标记一个对象,使其永远不会再成为响应式对象。有些值不应该被设置为响应式的,例如复杂的第三方类库,当渲染具有不可变的数据源的大列表时,跳过响应式转换可以提高性能
响应式数据的判断
isRef
:检查一个值是否为 ref
对象
isReactive
:检查一个对象是否由 reactive
创建的响应式代理
isReadonly
:检查一个对象是否由 readonly
创建的只读代理
isProxy
:检查一个对象是否由 reactive
或者 readonly
方法创建的代理
provide 和 inject
用于实现祖与后代组件间通信
<template> <h2>我是祖组件</h2> <h3>汽车信息</h3> <p>名称:{{name}}</p> <p>价格:{{price}}</p> <inject_component></inject_component> </template> <script> import {reactive,toRefs,provide} from 'vue' export default { name: "provide_component", setup(){ let car=reactive({ name:'宝马', price:'40w' }) provide('car',car) // 提供provide return{ ...toRefs(car) } } } </script> <template> <h2>我是孙组件</h2> <h3>汽车信息</h3> <p>名称:{{name}}</p> <p>价格:{{price}}</p> </template> <script> import {inject,toRefs,ref} from 'vue' export default { name: "inject_component", setup(){ let car=inject("car"); //使用inject接收 return{ ...toRefs(car) } } } </script>
过滤器
vue3 建议使用计算属性代替过滤器,如果需要全局过滤器可以自定义全局属性
// 定义全局属性
app.config.globalProperties.$filters = { currencyUSD(value) { return '$' + value } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!