vue3.0基础知识浅谈
vue3中 setup、ref、生命周期、计算属性、监听
vue3.0
首先创建vue3.0 项目
方法一: 命令行工具 (CLI)
查看@vue/cli版本 确保在4.5.0 以上 vue – version 或者 vue –v
下载@vue/cli npm install –g @vue/cli
npm create 项目名
方法二:Vite
npm版本 6.x
npm init vite@latest <project-name> --template vue
npm版本 7+,需要加上额外的双短横线
npm init vite@latest <project-name> -- --template vue
cd <project-name>
npm install
npm run dev
若要创建vue3+Ts项目 则将上述template vue换成template vue-ts
相比于vue2的变化
1.模板中可以没有根标签
2.main.js中变化
vue2引入的是vue的构造函数
vue3引入名为createApp的工厂函数
vue3中实例对象app比vue2中vm‘轻’没有vm身上那么多的属性和方法
// vue2引入的是vue的构造函数
// import Vue from "vue";
// vue3引入名为createApp的工厂函数
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
// 创建应用实例对象app
//(类似vue2中的vm,但app比vm‘轻’没有vm身上那么多的属性和方法)
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
组合API
一、setup
1.作用
- setup是vue3.0中新的配置项 值为函数,是 Composition API(组合API)的入口
- vue3.0中新的配置项,值为函数,组件中所用到的数据和方法…配置在setup中
- 在setup函数中定义的变量和方法最后都是需要 return 出去的 不然无法再模板中使用
2.返回值
- 第一种若返回一个对象,则对象中的属性,方法,在模板中均可以直接使用
- 第二种若返回一个渲染函数可以自定义渲染内容(例如 return ()=>h(‘h1’,’你好’))
3.注意点
1、setup在beforeCreate 和 created 之前执行,this是undefind
2、由于在执行 setup函数的时候,还没有执行 Created 生命周期方法,所以在 setup 函数中,无法使用 data 和 methods 的变量和方法
3、由于我们不能在 setup函数中使用 data 和 methods,所以 Vue 为了避免我们错误的使用,直接将 setup函数中的this修改成了 undefined
4、setup函数只能是同步的不能是异步的
5、vue2配置的(data、methods、computed…)中可以访问到setup中的属性和方法
6、setup中不能访问到vue2配置的(data、methods、computed…)
7、如果有重名 setup优先
8、setup不能是一个async函数,因为返回值不再是return 对象,而是promise,模板看不到return
4.参数
setup有两个参数
参数1:props 值为对象,包含组件外部传递过来且组件内部声明接收了的属性(大白话就是:父传子通过props,子组件必须写props进行接收,这样setup的第一个参数才能使用)
参数2:上下文是一个普通 JavaScript 对象,暴露了其它可能在 setup 中有用的值
- Context.attrs:值为对象,包含外部传递过来,但没有在props配置中声明的属性
- Context.slots:收到的插槽内容 插槽用法如下:
父组件中:
<Childll>
<template v-slot:vSlot8>
<span>插槽练习</span>
</template>
</Childll>
子组件中
<template>
<slot name="vSlot8"></slot>
</template>
- Context.emit:分发自定义事件的函数,相当于vue2.X中的this.$emit
子组件:
<template>
<div>
<button @click="clickBtn" class="btn-item">hi~</button>
</div>
</template>
<script>
export default {
setup (props, context) {
const clickBtn = () => {
context.emit("on-change", "hi~");
};
return { clickBtn}
}
</script>
父组件:
<template>
<div>
<Child @on-change="emitFn" />
</div>
</template>
<script>
import Child from "./Child.vue"
export default {
components: {
EmitChild
},
setup () {
const emitFn = v => {
console.log(v);
}
return { emitFn }
}
}
</script>
二、Ref函数
作用:定义响应式的数据
用法:
- 先引入ref import { ref } from ‘vue’;
- 定义数据: let username = ref(‘张三’) let job = ref({ type: ‘男’,age: 18})
- Js中操作定义的数据 username.value job.value.type
- 模板中读取数据 {{ username }} {{ job.type }}
三、reactive函数
作用:定义一个对象类型的响应式数据
用法:
- 先引入reactive import { reactive} from ‘vue’;
- 定义数据: let num= reactive ([1,2,3,4,5]) let job = ref({children: {type:‘男’,age: 18}})
- Js中操作定义的数据 num[0] job. children.type
四、Ref和Reactive的区别
- 定义数据:
Ref用来定义基本数据类型、Reactive定义对象\数组类型数据 - 原理:
Ref通过vue2中的Object.defineProperty()的get与set来实现响应式数据劫持
Reactive通过使用Proxy来实现响应式 - 使用
Ref定义数据后js中操作数据需要.value获取,模板读取不需要.value
Reactive定义数据后 操作和读取均不需要.value
五、生命周期
写法一、跟vue2.X写法一样,区别在于(beforeUnmount、unmount)名称不一样
写法二、写在setup里面的生命周期,通过组合API的形式
使用均需要引入
如: import { onBeforeMount } from ‘vue’
Setup(){ onBeforeMount( () =>{} ) }
具体对比:
Vue2.X | Vue3.0 |
---|---|
beforeCreate | 不需要(也可以理解为setup) |
created | 不需要(也可以理解为setup) |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestroy | onBeforeUnmount |
destroyed | onUnmount |
activated | onActivated |
deactivated | onDeactivated |
六、Hook
Hook:是一个函数、把setup函数中的组合api进行了封装,类似于vue2中的mixin,
Src目录下新建hooks文件夹 里面写各种逻辑的hook
例如:新建usePoint.js
// 引入文件所需
import { reactive, onMounted, onBeforeUnmount } from 'vue'
export default function(){
let point = reactive({
x:0,
y:0
}),
function savepoint(event){
point.x = event.pageX
point.y = event.pageY
}
onMounted(() => {
window.addEventListener('click',savepoint)
})
onBeforeUnmount(()=>{
window.removeEventListener('click',savepoint)
})
return point
}
其他vue文件需要用到此hook时
import usepoint from '路径'
// 然后在setup 中直接调用赋值
setup () {
let point = usepoint()
return {point}
}
七、toRef和torefs
有这么一个痛点
例:
定义一个英雄的对象,渲染时在模板中使用会重复数次写Hero.
<template>
<p>姓名:{{Hero.name}}</p>
<p>年龄:{{Hero.age}}</p>
<p>技能:{{Hero.job.j1.speak}}</p>
</template>
<script>
import { reactive} from "vue";
export default {
setup() {
let Hero = reactive({
name: '李四',
age: 18,
job: {
j1: {
speak: '你好'
}
}
})
return {
Hero
}
}
}
</script>
解决上述痛点:
toRef
作用:创建一个ref对象,或者可以说将一个不是ref的变为ref
用法: 1. 引入
import { toRef } from “vue”;
这样模板中就是可以直接使用{{name}}
toRefs
toRef一次只能处理一个属性而toRefs可以处理多个
import { toRefs } from "vue";
setup() {
return {
...toRefs(Hero)
}
}
这样就解决一开始的痛点在模板中多次书写Hero.
八、toRaw
- 将一个由reactive生成的响应式对象转为普通对象(ref生成的不行)
- 操作场景 用于读取响应式数据,后续操作不会引起页面数据变化
- 用法: toRaw(需要转换的对象的)
九、markRaw
- 标记一个对象永远不作为响应式对象
- 用法 markRaw(需要标记的对象)
十、customRef
创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显式控制,customRef里面需要写一个函数,函数接收两个参数,并且应该返回一个带有 get 和 set 的对象
track () 在get中通知vue追踪return出去的数据变化
tigger() 在set中改完数据后 通知vue重新解析模板
<template>
<input v-model="keyword" />
<h3>{{keyword}}</h3>
</template>
<script>
import { customRef } from "vue";
export default {
name: 'Testvue',
setup() {
function myref(value,time = 1000) {
let timer;
return customRef((track, tigger) => {
return {
get() {
track() // 通知vue追踪value的变化
return value
},
set(newValue) {
clearTimeout(timer)
timer = setTimeout(() =>{
value = newValue
tigger() // 改完数据后 通知vue重新解析模板
}, time)
}
}
})
}
let keyword = myref('hello', 500)
return {
keyword
}
}
};
十一、provide和inject(祖孙组件之间通信)
父组件用provide提供数据 后代组件用inject使用数据
例 父组件:
import { reactive, provide} from "vue";
setup() {
let person = reactive({
firstName: '张',
lastName: '三'
})
provide('passData', person)
}
后代组件:
import {inject} from "vue";
setup() {
let obj = inject('passData')
return {
obj
}
}
十二、Computed 计算属性
有简写和完整写法之分,完整写法考虑读写
// 计算属性 简写 -- 单纯的读取
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]
}
})
十三、watchEffect
不用指明监听那个属性的变化,回调函数中用到哪个属性,就监听那个属性变化
watchEffect(() => {
console.log(person.firstName);
})
十四、watch监听
1、监听ref所定义的一个响应式数据
参数:
- 监听谁
- 回调函数
- 配置对象
<template>
<h3>当前数值:{{ sum }}</h3>
<button @click="sum++">增加</button>
</template>
<script>
import { ref, watch } from "@vue/runtime-core";
export default {
setup() {
let sum = ref(0);
watch(
sum,
(newValue, oldValue) => {
console.log(newValue, oldValue);
},
{
immediate: true, // 立即监听
deep: true, // 深度监听
}
);
return {
sum,
};
},
};
</script>
2、监听ref所定义的多个响应式数据
当监听多个响应式数据时,将多个数据放在一个数组里面,这样监听的newValue和oldValue都也都是也数组的形式呈现
<template>
<h3>当前数值:{{ sum }}</h3>
<button @click="sum++">增加</button>
<h3>标题:{{ title }}</h3>
<button @click="title+='~'">增加</button>
</template>
<script>
import { ref, watch } from "@vue/runtime-core";
export default {
setup() {
let sum = ref(0);
let title = ref("hi~");
// 监听多个
watch(
[sum,title],
(newValue, oldValue) => {
console.log(newValue, oldValue);
},
{
immediate: true, // 立即监听
deep: true, // 深度监听
}
)
return {
sum,
title,
};
},
};
</script>
3、监听reactive所定义的响应式数据的全部属性,
无法正确获取oldValue,并且强制开启了深度监听。
4、监听reactive所定义的响应式数据的某个属性
第一个参数要以回调函数返回写法
<template>
<h3>姓名:{{Hero.username}}</h3>
<h3>年龄:{{Hero.age}}</h3>
<button @click="Hero.age++">改变年龄</button>
<button @click="Hero.username += '~'">改变姓名</button>
</template>
<script>
import { reactive, watch } from "@vue/runtime-core";
export default {
setup() {
let Hero = reactive({
username: '李四',
age: 18,
job: {
j1: {
speak: '你好'
}
}
})
// reactive所定义的响应式数据的某个属性
watch(
()=>Hero.age, // 以回调形式拿到监听的属性
(newValue, oldValue) => {
console.log(newValue, oldValue);
},
{
immediate: true, // 立即监听
deep: true, // 深度监听
})
return {
Hero
};
},
};
</script>
5、监听reactive所定义的响应式数据的多个属性
如果监听的属性嵌套层次比较深 则需要开启深度监听
watch(
[()=>Hero.username, ()=>Hero.age, () =>Hero.job], // 以回调形式拿到监听的属性
(newValue, oldValue) => {
console.log(newValue, oldValue);
},
{
immediate: true, // 立即监听
deep: true, // 深度监听
})
更多推荐
所有评论(0)