- Vue3 中文文档(新) Vue.js - 渐进式 JavaScript 框架 | Vue.js
vue3的优点:
- 首次渲染更快
- diff 算法更快
- 内存占用更少
- 打包体积更小
- 更好的 Typescript 支持
Composition API
组合 API
首先理解一下vite 构建工具:
vite是一种新型前端构建工具,能够显著提升前端开发体验。
对比 webpack:
- webpack需要查找依赖,打包所有的模块,然后才能提供服务,更新速度会随着代码体积增加越来越慢
而vite 的原理是:
- 使用原生 ESModule 通过 script 标签动态导入,访问页面的时候加载到对应模块编译并响应
基于 webpack
构建项目 与 基于 vite
构建项目,谁更快体验更好?vite
基于 webpack
的 vue-cli
也可以创建 vue 项目,只是慢一点而已。
6.进入项目目录,安装依赖,启动项目即可。npm i pnpm run dev或npm run dev启动项目
Vue3提供两种组织代码逻辑的写法:
- 通过data、methods、watch 等配置选项组织代码逻辑是
选项式API
写法 - 所有逻辑在setup函数中,使用 ref、watch 等函数组织代码是
组合式API
写法
一、组合式api
- 在setup中通过vue提供的函数组织代码实现功能,就是组合式API写法。
- 组合式API的好处:可复用,可维护
- ref 就是一个组合式API
二、生命周期函数
Vue2和Vue3生命周期对比
三、Vue3常用核心语法
1.setup函数
特点:
(1)setup函数是vue的特有选项,是组合式api的入口函数
(2)从生命周期看,它在beforeCreate之前执行
(3)作为入口函数,必须要有return
(4)没有this值
注:setup 中返回的对象数据不是响应式的,需要使用ref和reactive转成响应式
代码示例:
<template>
<div>
===vue3
===={{ num }}
===={{ obj.age }}==={{ obj.name }}
<button @click="btn">按钮</button>
</div>
</template>
<script>
import {ref,reactive} from 'vue'
export default {
name:'',
setup(){
// ref定义响应式数据,不限数据类型 更改数据需要.value
let num=ref(10)
// reactive定义响应式数据,只限于复杂数据类型 更改数据不需要.value
let obj=reactive({age:12,name:'jack'})
const btn=()=>{
num.value+=2
obj.age=18
obj.name='rose'
console.log(num.value,obj.age,obj.name,99);
}
return {num,obj,btn}
}
}
</script>
<style lang='less' scoped>
</style>
2.setup语法糖:
作用:简化 setup 固定代码 ,让代码更简洁
使用:
(1)直接在script标签里面写setup 不用return 和 export default
(2)导入组件之后可以直接使用,不用注册
代码示例:
<template>
<div>
===vue3
===={{ num }}
===={{ obj.age }}==={{ obj.name }}
<button @click="btn">按钮</button>
</div>
</template>
<script setup>
// setup写在script标签上就是语法糖,优化代码,不需要导入导出,在导入组件的时候也不需要注册
import { ref, reactive } from 'vue'
// ref定义响应式数据,不限数据类型 更改数据需要.value
let num = ref(10)
// reactive定义响应式数据,只限于复杂数据类型 更改数据不需要.value
let obj = reactive({ age: 12, name: 'jack' })
const btn = () => {
num.value += 2
obj.age = 18
obj.name = 'rose'
console.log(num.value, obj.age, obj.name, 99);
}
</script>
<style lang='less' scoped>
</style>
3.ref函数
作用:
(1)定义响应式数据,所有数据类型都可以使用(除复杂数据类型外,其他数据类型常用ref( ) )
使用步骤:
1.从vue中导入ref
2.在 setup 函数中,使用 ref 函数,传入数据,返回一个响应式数据
3.使用 ref 创建的数据,js 中需要 .value来取值 ,template模板 中可省略
(2)获取DOM元素,相当于Vue2中的自定义指令
使用步骤:
1.从vue中导入ref
2.模板中建立关联: ref="自定义属性名"
3.使用: 自定义属性名.value
代码示例:
<script setup>
// 常用的 onMounted 组件渲染完毕:发请求,操作dom,初始化图表...
import {ref, onMounted } from "vue";
// 生命周期函数:组件渲染完毕
onMounted(()=>{
console.log('onMounted触发了')
console.log(dom,'dom111');
})
// 默认值是null,需要在渲染完毕后访问DOM属性。
let dom=ref(null)
const btn=()=>{
console.log(dom.value,'dom222');
}
</script>
<template>
<div>生命周期函数
<h1 ref="dom">我是标题h1</h1>
<button @click="btn">按钮操作dom</button>
</div>
</template>
4.reactive函数
作用:定义复杂数据类型的响应式数据,不能定义简单数据类型
使用步骤:
1.从vue中导入 reactive
2.在 setup 函数中,使用 reactive 函数,传入复杂数据类型数据,返回一个响应式数据
3.使用 reactive 创建的数据,js 和 template 模板中都可以直接使用
5.computed函数
作用:计算属性
使用步骤:
1.从vue中导入 computed
2.在 setup 函数中,使用 computed 函数,参数是一个函数,函数返回计算好的数据
3.计算好的数据在 js 中需要.value取值,template 模板中可以直接使用
代码示例:
<script setup >
import {ref,reactive,computed} from 'vue'
let arr=reactive([1,2,3,4,5])
let val=ref(1)
// computed动态求和 这里数组发生改变,computed计算属性就会触发
const total=computed(()=>{
return arr.reduce((sum,item)=> sum+Number(item) ,0)
})
const handel=()=>{
arr.push(val.value)
}
</script>
<template>
<div>
御剑乘风来,除魔天地间!===vue3
======{{ total }}======={{ arr }}
<input type="text" @blur="handel" v-model="val" placeholder="请输入数字">
</div>
</template>
<style lang='less' scoped>
</style>
6.watch函数
作用:监听数据的变化
使用步骤:
1.从vue中导入 watch
2.在 setup 函数中,使用 watch 函数,参数有以下几种情况:
(1)监听简单数据类型,参数为:值,(newVal,oldVal)=> { } ,配置项
(2)监听复杂数据类型,参数为:值,(newVal)=> { } ,配置项
(3)监听对象中某个属性,参数为:()=>对象.属性,(newVal,oldVal)=> { } ,配置项
(4)同时监听多个数据,参数为:[数据1,数据2...],(newVal,oldVal)=> { } ,配置项
代码示例:
(1)监听简单数据类型
// watch(需要监听的数据||函数,数据改变执行函数,配置对象) 来进行数据的侦听
// 1 使用 watch 监听一个简单数据类型
import {ref,watch } from 'vue'
let num=ref(0)
// setTimeout只执行一次
setTimeout(()=>{
num.value++
},1000)
// 监听num的变化
watch(num,(nerval,olduvai)=>{
console.log(nerval,olduvai,'num发生改变了');
})
(2)监听复杂数据类型
// 2 使用 watch 监听响应式对象数据中的一个属性(简单)
import {reactive,watch } from 'vue'
let obj=reactive({age:18,name:'jack'})
const btn=()=>{
obj.age+=2
obj.name='rose'
}
// 监听obj的变化 ,监听复杂数据类型的时候,只有新值newVal,没有旧值oldVal
watch(obj,(newVal)=>{
console.log(obj,newVal);
})
(3)监听对象中某个属性
//3 使用 watch 监听响应式对象数据中的一个属性(监听复杂数据类型)
import { reactive, watch } from "vue";
const obj = reactive({
num: 33,
info: {
name: "jack",
age: 18,
},
});
const btn=()=>{
obj.num+=10
obj.info.age+=2
obj.info.name='rose'
}
watch(()=>obj.info.age,(newVal,oldVal)=>{
console.log(obj.info.age,obj.info.name,newVal,oldVal);
})
(4)同时监听多个数据
// 4 使用 watch 监听多个数据
import {ref,reactive,watch } from 'vue'
let num=ref(1)
let obj=reactive({age:18,name:'jack'})
const btn=()=>{
num.value+=1
obj.age+=2
obj.name='rose'
}
// 同时监听多个数据类型 newVal是一个数组
watch([()=>obj.age,num],(newVal,oldVal)=>{
console.log('111',newVal,oldVal);
})
7.ref操作组件-defineExpose函数
作用:使用 <script setup> 的组件是默认关闭的,组件实例使用不到顶层的数据和函数。通过defineExpose函数可以将子组件中的数据和方法暴露出去,父组件直接通过ref就能调用子组件中的数据和方法
使用步骤:
1.子组件: defineExpose({变量名,函数名,... })
2.父组件: ref名.value.xxx 直接调用
8.父传子-defineProps函数
作用:实现父传子组件通讯
使用步骤:
1.父组件:和vue2语法一样正常传值
2.子组件:用defineProps接收
3.在js中,通过defineProps的返回值来接收使用数据,template 模板中可以直接使用
9.子传父-defineEmits函数
作用:实现子传父组件通讯
使用步骤:
1.子组件:
通过defineEmits声明事件名称,并接收返回值emit
根据条件触发emit('事件名称','传值'),进行传值
2.父组件:
模板中接收@事件名="新函数"
js中新函数可以通过参数e,接收传值
10.跨级组件通讯provide与inject函数
作用:通过provide和inject函数实现简单的跨级组件通讯
使用步骤:
1.祖先组件
(1)从 vue 中导出 provide 函数
(2)provide('变量名', 变量值);
2.子/孙组件
(1)从 vue 中导出 inject 函数
(2)const value = inject('变量名')
Q:如何通过provide和inject实现响应式数据传值?
1.祖先组件先传变量和函数给子/孙组件
2.子/孙组件接收函数并调用传值
3.祖先组件中的函数接收传值,并对变量重新赋值
父组件示例代码:
<script setup>
// provide和inject是解决跨级组件通讯的方案
// provide 提供后代组件需要依赖的数据或函数
// inject 注入(获取)provide提供的数据或函数
import Son03 from "./components/Son03.vue";
import { ref, reactive, provide } from 'vue';
const count = ref(100)
const obj = reactive({ age: 18, name: '小花' })
const addFn = (e) => {
obj.name = e
console.log(e);
}
// provide 提供后代组件需要依赖的数据或函数
// provide(键,值) 传值
provide('newCount', count.value) //祖先组件向子组件和sun组件传值
provide('newObj', obj)
provide('newAddFn', addFn)
</script>
<template>
<div>
<h3>我是父组件===vue3</h3>
<div>余额:{{ count }}元</div>
<div>姓名:{{ obj.name }}</div>
<hr />
<Son03></Son03>
</div>
</template>
<style lang='less' scoped>
</style>
子组件示例代码:
<script setup >
// 导入sun组件
import sun from "./sun.vue";
</script>
<template>
<div>
<div>我是子组件===Son03</div>
<hr />
<sun></sun>
</div>
</template>
<style lang='less' scoped>
</style>
孙组件示例代码:
<script setup >
// 跨级sun组件接收爷爷传过来的值count和obj addFn函数
import { inject } from 'vue';
let newCount = inject('newCount')
let newObj = inject('newObj')
let newAddFn = inject('newAddFn')
console.log(newCount, 111);
console.log(newObj, 222);
console.log(newAddFn, 333);
const btn = (e) => {
console.log(e, 444);
newAddFn('小红')
}
</script>
<template>
<div>
<div>我是sun组件===sun</div>
<div>{{ newCount }}</div>
<div>{{ newObj }}</div>
<div>{{ newAddFn }}</div>
<button @click="btn">按钮</button>
</div>
</template>
<style lang='less' scoped>
</style>
11.保持响应式 toRefs函数
作用:在使用reactive创建的响应式数据被展开或解构的时候使用toRefs保持响应式
使用步骤:
1.从 vue 中导出 toRefs 函数
2.将被展开或解构的数据作为参数传入toRefs 函数
3.解构后的数据是一个变量,依然可以保持响应式,但js中需要通过.value取值,模板中不用
<script setup >
import {reactive, toRefs} from 'vue'
// 当去解构和展开响应式数据对象使用 toRefs 保持响应式
const user =reactive({name:'tom',age:'18',gender:'男'})
// const {name,age,gender}=user //这种解构的写法 响应式失效
const {name,age,gender}=toRefs(user) //在解构对象的时候 使用了toRefs 才能保持数据是响应式的
const btn=()=>{
user.name='rose'
user.age=28
user.gender='女'
}
</script>
<template>
<div>
御剑乘风来,除魔天地间!===vue3
<!-- ===姓名:{{user.name}}===年龄:{{ user.age }}===性别:{{ user.gender }} -->
===姓名:{{name}}===年龄:{{ age }}===性别:{{ gender }}
<button @click="btn">改变数据按钮</button>
</div>
</template>
<style lang='less' scoped>
</style>