在Vue3.2 版本之前 变量函数必须return出来非常繁琐,而在 Vue3.2 中只需要
在 script 标签上加上 setup 属性就无需return出来,非常方便。
使用setup语法糖后,不用写setup函数;组件只需要引入不需要注册;属性和方法也不需要再返回,也不用写export default,可以直接在template模板中使用。
只需在 script 标签上写上setup
代码如下(示例):
<template>
</template>
<script setup>
</script>
setup语法糖提供了三个新的API
来供我们使用:defineProps
、defineEmits
和useContext
defineProps:子组件接收父组件中传来的props
defineEmits:子组件调用父组件中的方法
defineExpose:子组件暴露属性,可以在父组件中拿到
父组件如下:
<template>
<child :name='name'/>
</template>
<script setup>
import {ref} from 'vue'
import child from './child.vue' // 引入子组件
let name= ref('父组件')
</script>
子组件如下:
<template>
<span>{{props.name}}</span>
</template>
<script setup>
import { defineProps } from 'vue'
const props = defineProps({ // 声明props
name: {
type: String,
default: '子组件'
}
})
// 或者
//const props = defineProps(['name'])
</script>
父组件如下:
<template>
<child @but="clickBut" />
</template>
<script setup>
import {reactive} from 'vue'
// 导入子组件
import child from './child.vue'
const data = reactive({
flg: false,
})
const clickBut= () => {
data.flg= false
}
子组件如下:
<template>
<a-button @click="but1">
子组件按钮
</a-button>
</template>
<script setup>
import { defineEmits } from 'vue';
// emit
const emit = defineEmits(['but'])
/**
* 方法
*/
// 点击确定按钮
const but1 = () => {
emit('but');
}
</script>
父组件如下:
<template>
<child ref="mynum"></my-comp>
<button @click="onButton">获取子组件中暴露的值</button>
</template>
<script setup>
import {ref} from 'vue';
import child from './child.vue' // 导入子组件
//注册ref,获取组件
const myComponent = ref();
function onButton(){
//在组件的value属性中获取暴露的值
console.log(mynum.value.num) //0
}
</script>
注意:但在setup中立即使用获取为为undefined
子组件如下:
<template>
<div>子组件中的值{{num}}</div>
<button @click="onButton">数值加1</button>
</template>
<script setup>
import {ref,defineExpose} from 'vue';
let num= ref(0);
function onButton(){
num.value++;
}
//暴露出子组件中的属性
defineExpose({
num
})
</script>
接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象具有指向内部值的单个 property .value。
代码如下(示例):
<template>
</template>
<script setup>
import {ref} from 'vue';
let num= ref(0);
console.log(num.value) // 0
</script>
reactive 用于为对象添加响应式状态。获取数值的时候不用加.value
代码如下(示例):
<template>
</template>
<script setup>
import {reactive} from 'vue'
//数据
let person = reactive({
name:'李四',
age:18,
job:{
type:'前端工程师',
salary:'9000',
a:{
b:{
c:'字符串'
}
}
},
hobby:['vue','js','css']
})
console.log(person.name,person.job.type); //李四,前端工程师
const {name,age} = person
console.log(name,age); //李四,18
</script>
注意:直接 const {name,age} = person 结构会失去响应式,需要加toRefs
代码如下(示例):
<template>
</template>
<script setup>
import {reactive,toRefs} from 'vue'
//数据
let person = reactive({
name:'李四',
age:18,
job:{
type:'前端工程师',
salary:'9000',
a:{
b:{
c:'字符串'
}
}
},
hobby:['vue','js','css']
})
const { name,age} = toRefs(person)
console.log(name.value,age.value);//李四,18
</script>
使用toRefs解构不会失去响应式,但需要加.value
watchEffec它是立即执行的,在页面加载时会主动执行一次,只能访问当前最新的值访问不到修改之前的值,另外在watchEffect 中只有使用到了变量,它才会自动进行追踪
代码如下(示例):
<template>
<button @click="sum++">点我+1</button>
<button @click="person.name+='~'">修改姓名</button>
</template>
<script setup>
import {ref,reactive,watch,watchEffect} from 'vue'
//数据
let sum = ref(0)
let person = reactive({
name:'张三',
})
watchEffect(()=>{
const value1 = sum.value
const value2 = person.name
console.log('watchEffect所指定的回调执行了',value1 ,value2 )
})
</script>
注意:打印的数值都是改变后最新的值
watch运行的时候不会立即执行,可以最新值和修改之前的值,可以添加配置项
配置项:
1.immediate:配置watch属性是否立即执行,值为 true 时,一旦运行就会立即执行,值为false时,不会立即执行。
2.watch : 是否深度监听,值为 true 时,可以监听对象所有属性,值为 false 时,则必须指定到具体的属性上。
代码如下(示例):
情况一:监视ref所定义的一个响应式数据
<template>
<h2>当前求和为:{{sum}}</h2>
<button @click="sum++">点我+1</button>
</template>
<script setup>
import {ref,reactive,watch} from 'vue'
//数据
let sum = ref(0)
watch(sum,(newValue,oldValue)=>{
console.log('sum变了',newValue,oldValue)
},{immediate:true})
</script>
//情况二:监视ref所定义的多个响应式数据
<template>
<h2>当前求和为:{{sum}}</h2>
<button @click="sum++">点我+1</button>
<hr>
<h2>当前的信息为:{{msg}}</h2>
<button @click="msg+='!'">修改信息</button>
</template>
<script setup>
import {ref,reactive,watch} from 'vue'
//数据
let sum = ref(0)
let msg = ref('watch好啊')
watch([sum,msg],(newValue,oldValue)=>{
console.log('sum或msg变了',newValue,oldValue)
},{immediate:false})
</script>
情况三:监视reactive所定义的一个响应式数据的全部属性
<template>
<h2>姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<h2>职位:{{person.job.j1.salary}}K</h2>
<button @click="person.name+='~'">修改姓名</button>
<button @click="person.job.j1.salary+='123'">跳槽</button>
</template>
<script setup>
import {ref,reactive,watch} from 'vue'
let person = reactive({
name:'张三',
job:{
j1:{
salary:'前端'
}
}
})
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
},{deep:false}) //此处的deep配置无效
</script>
此处无法正确的获取oldValue,强制开启了深度监视(deep配置无效)
情况四:监视reactive所定义的一个响应式数据中的某个属性
<template>
<h2>姓名:{{person.name}}</h2>
<button @click="person.name+='~'">修改姓名</button>
</template>
<script setup>
import {ref,reactive,watch} from 'vue'
let person = reactive({
name:'张三',
job:{
j1:{
salary:'前端'
}
}
})
watch(()=>person.name,(newValue,oldValue)=>{
console.log('person的name变化了',newValue,oldValue)
})
</script>
情况五:监视reactive所定义的一个响应式数据中的某些属性
<template>
<h2>姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<button @click="person.name+='~'">修改姓名</button>
<button @click="person.age++">增长年龄</button>
</template>
<script setup>
import {ref,reactive,watch} from 'vue'
let person = reactive({
name:'张三',
age:18,
job:{
j1:{
salary:'前端'
}
}
})
watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
console.log('person的name或age变化了',newValue,oldValue)
})
</script>
与vue2中的写法一致,并且需要引入computed
代码如下(示例):
<template>
</template>
<script setup>
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]
}
})
</script>
vue3 中的 hooks 就是函数的一种写法,就是将文件的一些单独功能的js代码进行抽离出来,放到单独的js文件中,和 vue2 中的 mixin 有点类似
hooks的用法:一般会在src中创建一个hooks文件夹,专门用来存放hook文件来复用
某项目中的hook实例:
hooks目录下代码,将弹出的属性、展示、关闭封装复用
import {reactive} from 'vue'
import { DialogModel } from "@/type/BastType";
export default function useDialog(){
//定义弹框属性
const dialog = reactive<DialogModel>({
title:'',
visible:false,
width:630,
height:280
})
//展示
const onShow = () =>{
dialog.visible = true;
}
//关闭
const onClose = () =>{
dialog.visible =false;
}
//确定
const onConfirm = () =>{
dialog.visible = false;
}
return {
dialog,
onShow,
onClose,
onConfirm
}
}
弹出组件
<template>
<SysDialog
:title="dialog.title"
:width="dialog.width"
:height="dialog.height"
:visible="dialog.visible"
@onClose="onClose"
@onConfirm="confirm"
>
<template v-slot:content>
<el-tree
ref="parentTree"
:data="treeData.data"
node-key="id"
:props="defaultProps"
default-expand-all
:highlight-current="true"
:expand-on-click-node="false"
@node-click="handleNodeClick"
>
<template #default="{ node, data }">
<div class="custom-tree-container">
<!-- 长度为0说明没有下级 -->
<span v-if="data.children.length == 0">
<DocumentRemove style="width: 1.3em; height: 1.3em; margin-right: 5px;color: #8c8c8c;"></DocumentRemove>
</span>
<!-- 点击展开和关闭 -->
<span v-else @click.stop="openBtn(data)">
<component style="width: 1.1em; height: 1.1em; margin-right: 5px;color: #8c8c8c;" :is="data.open ? Plus : Minus" />
</span>
<span>{{ node.label }}</span>
</div>
</template>
</el-tree>
</template>
</SysDialog>
</template>
<script setup lang='ts'>
import {DocumentRemove,Plus,Minus} from '@element-plus/icons-vue'
import SysDialog from '@/components/SysDialog.vue';
import useDialog from '@/hooks/useDialog'; //自定义hooks
import useParent from '@/composables/department/useParent';
//弹框属性
const { dialog, onClose, onShow } = useDialog()
//子组件传值给父组件
const emit = defineEmits(['select'])
//弹框确定事件
const confirm = () => {
emit('select',selectNode)
onClose();
}
//供父组件调用,显示弹框
const show = async () => {
//获取树的数据
await getTreeData();
//设置弹框属性
dialog.title = '选择上级部门'
dialog.height = 420;
dialog.width = 300;
//显示
onShow();
}
//把方法暴露出去
defineExpose({
show
})
//树相关数据
const { treeData, defaultProps, handleNodeClick, getTreeData ,openBtn,parentTree,selectNode} = useParent();
</script>
<style lang="scss">
</style>
setup 语法糖中可直接使用 await,不需要写 async , setup 会自动变成 async setup
代码如下(示例):
<script setup>
import Api from '../api/Api'
const data = await Api.getData()
console.log(data)
</script>
vue3.2 中 provide 和 inject 的用法和 vue2 中用法相似;只不过在vue3.2中 为了增加响应式数据的处理,我们可以在定义值的时候使用 ref 或者 reactive;
父组件代码:
<template>
<div class="app">
<h3>我是父组件,{{name}}--{{price}}</h3>
<Child/>
</div>
</template>
<script setup>
import { reactive,toRefs,provide } from 'vue'
import Child from './components/Child.vue'
let car = reactive({name:'奔驰',price:'40W'})
const {name,price}=toRefs(car)
provide('car',{
car,
changeName: (e) => {
name.value = e
}
}) //给自己的后代组件传递数据
</script>
<style>
.app{
background-color: gray;
padding: 10px;
}
</style>
子组件代码:
<template>
<div class="child">
<h3>我是Child组件(子)</h3>
<Son/>
</div>
</template>
<script setup>
import Son from './Son.vue'
</script>
<style>
.child{
background-color: skyblue;
padding: 10px;
}
</style>
孙子组件代码:
<template>
<div class="son">
<h3>我是Son组件(孙), 拿到爷爷组件传过来的值{{car.car.name}}--{{car.car.price}}</h3>
<button @click="change">向爷爷组件传参</button>
</div>
</template>
<script setup>
import {inject} from 'vue'
let car = inject('car')
function change(){ //向爷爷组件传参
car.changeName('宝马')
}
</script>
<style>
.son{
background-color: orange;
padding: 10px;
}
</style>
原来的vue2路由是通过this. r o u t e 和 t h i s . route和this. route和this.router来控制的。现在vue3有所变化,useRoute相当于以前的this. r o u t e ,而 u s e R o u t e r 相当于 t h i s . route,而useRouter相当于this. route,而useRouter相当于this.router
代码如下(示例):
<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: '/',
query: {
name: 'dx',
age: 18
}
})
router.push({
name: 'Home',
params: {
name: 'dx',
age: 18
}
})
</script>
1、setup() : 开始创建组件之前,在 beforeCreate 和 created 之前执行,创建的是 data 和 method
2、onBeforeMount() : 组件挂载到节点上之前执行的函数;
3、onMounted() : 组件挂载完成后执行的函数;
4、onBeforeUpdate(): 组件更新之前执行的函数;
5、onUpdated(): 组件更新完成之后执行的函数;
6、onBeforeUnmount(): 组件卸载之前执行的函数;
7、onUnmounted(): 组件卸载完成后执行的函数;
8、onActivated(): 被包含在 中的组件,会多出两个生命周期钩子函数,被激活时执行;
9、onDeactivated(): 比如从 A 组件,切换到 B 组件,A 组件消失时执行;
10、onErrorCaptured(): 当捕获一个来自子孙组件的异常时激活钩子函数。
vue2 -------> vue3
beforeCreate --------> setup(()=>{})
created --------> setup(()=>{})
beforeMount --------> onBeforeMount(()=>{})
mounted --------> onMounted(()=>{})
beforeUpdate --------> onBeforeUpdate(()=>{})
updated --------> onUpdated(()=>{})
beforeDestroy --------> onBeforeUnmount(()=>{})
destroyed --------> onUnmounted(()=>{})
activated --------> onActivated(()=>{})
deactivated --------> onDeactivated(()=>{})
errorCaptured --------> onErrorCaptured(()=>{})```