Composition API
以后开发不再用options api 而是composition api,这个api其实就是setup函数
compositionAPI:组合API
optionsAPI:选项API
options和composition对比
1-如上optionsAPI实际上就是在操控data中的数据,但是对它的操作遍布于各种api中,如methods,computed,watch等等。 弊端就是太分散了不利于分析代码等。
2-compositionAPI就是把对同个内容的操作全部写到一个函数内,然后这个函数还可以被很简单的抽取出进行复用。
认识compositionApi
<template>
<!-- template中ref对象自动解包 -->
<h2>数字:{{ counter }}</h2>
<button @click="add">+1</button>
<button @click="sub">-1</button>
</template>
<script>
import {ref} from "vue"
//import {reactive} from "vue"
//import {reactive,ref} from "vue" 这种写法同时导入也可以
export default {
setup(){
//注意此时counter其实就是一个ref对象了,而不是简单的100,所以想使用这个100,必须通过counter.value
let counter = ref(100)
// function add(){}
const add =()=>{
counter.value +=1
}
// function sub(){}
const sub =()=>{
counter.value -=1
}
return{
counter,
add,
sub
}
}
}
</script>
<style scoped>
</style>
步骤:
1-在script标签内书写setup函数
2-在setup函数中声明变量和使用箭头函数(普通函数也可以)声明会发生的事件
3-setup中所有声明的东西,必须return返回出去才可以使用
4-我们点击按钮发现没反应,其实普通数据counter已经变化了,但是它不是响应式数据不会被劫持代理,不会在页面上实时改变
5.1-导入vue提供的ref方法,使用ref包裹住数据,即可实现响应式。
5.1.1使用ref后,在script中必须通过counter.value才能取到真正的值,在template中的插值语法中不需要,因为有vue内部会自动解包。(解包就是自动取出其对象的value属性)
//注意此时counter其实就是一个ref对象了,而不是简单的100,所以想使用这个100,必须通过counter.value
5.2通过reactive函数
react就是回应,反应的意思,reactive就是响应式,因为我们在setup中写的数据是普通数据,不会像在optionsAPI的data中的数据那样被vue劫持,所以是不会在页面中自动响应更新的。
需要我们手动通过reactive劫持(其实data响应式原理的底层也是通过reactive函数),注意:reactive函数必须传入复杂类型的参数,如上的传入对象,而不是是简单的字符串或者一个数字值。
什么时候用ref,什么时候用reactive
这里是coderwhy老师总结出的经验,我以后也就这样写,其实只要你需要响应式数据,ref和reactive都可以完成,但是各有各的优点。
<template>
<div>
<form>
账号: <input type="text" v-model="account.username">
密码: <input type="password" v-model="account.password">
</form>
<form>
账号: <input type="text" v-model="username">
密码: <input type="password" v-model="password">
</form>
<hr>
<show-info :name="name" :age="age"></show-info>
</div>
</template>
<script>
import { onMounted, reactive, ref } from 'vue'
import ShowInfo from './ShowInfo.vue'
export default {
components: {
ShowInfo
},
data() {
return {
message: "Hello World"
}
},
setup() {
// 定义响应式数据: reactive/ref
// 强调: ref也可以定义复杂的数据
const info = ref({})
console.log(info.value)
// 1.reactive的应用场景
// 1.1.条件一: reactive应用于本地的数据
// 1.2.条件二: 多个数据之间是有关系/联系(聚合的数据, 组织在一起会有特定的作用)
const account = reactive({
username: "coderwhy",
password: "1234567"
})
const username = ref("coderwhy")
const password = ref("123456")
// 2.ref的应用场景: 其他的场景基本都用ref(computed)
// 2.1.定义本地的一些简单数据
const message = ref("Hello World")
const counter = ref(0)
const name = ref("why")
const age = ref(18)
// 2.定义从网络中获取的数据也是使用ref
// const musics = reactive([])
const musics = ref([])
onMounted(() => {
const serverMusics = ["海阔天空", "小苹果", "野狼"]
musics.value = serverMusics
})
return {
account,
username,
password,
name,
age
}
}
}
</script>
<style scoped>
</style>
来自本地的,有关联的数据就用reactive,为什么呢?
因为有关联的数据,比如账号密码,你使用reactive的方法就直接account.username和account.password即可,更方便使用。
其他场景一般都用ref函数
比如来自服务器的数据,使用ref的话,如上代码直接music.value=serverMusics即可,如果是使用reactive函数,那么你没法去把服务器的数据搞进去,或者说需要一个一个遍历进去,很麻烦。
hooks文件夹是什么?
https://blog.csdn.net/JaneLittle/article/details/127127644
vue3
借鉴 react hooks
开发出了 Composition API ,所以也就意味着 Composition API 也能进行自定义封装 hooks
。
vue3
中的 hooks
就是函数的一种写法,就是将文件的一些单独功能的js
代码进行抽离出来,放到单独的js文件中,或者说是一些可以复用的公共方法/功能。其实 hooks
和 vue2
中的 mixin
有点类似,但是相对 mixins
而言, hooks
更清楚复用功能代码的来源, 更清晰易懂。
安装Vue-devtool
作用:方便调试
1-直接在chorm商店下载(某些原因正常情况下打不开)
安装后如果不生效,重启下浏览器
2-找个安装教程手动安装,去github下载源码然后打包,拖到chorm拓展内。
认识readonly只读函数(了解)
它的原理就是劫持了对象的set方法,让它无法被修改。
问题:子组件可以修改来自父组件通过父子通信,传递过来的数据,即修改props内的数据(如对象)。
规范准则:虽然这是可行的,但是不符合单项数据流的准则,如父组件将此数据传递给了3个子组件,然后其中一个子组件修改了数据,那么父组件根本不知道是谁改的,非常不利于维护。 这个准则在react内也要遵守
实在要修改这个数据呢?
在子组件内通过emit发送自定义事件给父组件,由父组件进行修改。
问题:当其他人在编写子组件的时候,他不知道这个单向数据流的准则,修改了数据应该怎么避免呢?
解决:在父组件内使用readonly函数包裹住需要传出到子组件的数据即可。那么这个数据将不能被修改。
app.vue
<template>
<h2>App: {{ info }}</h2>
<show-info :info="info"
:roInfo="roInfo"
@changeInfoName="changeInfoName"
@changeRoInfoName="changeRoInfoName">
</show-info>
</template>
<script>
import { reactive, readonly } from 'vue'
import ShowInfo from './ShowInfo.vue'
export default {
components: {
ShowInfo
},
setup() {
// 本地定义多个数据, 都需要传递给子组件
// name/age/height
const info = reactive({
name: "why",
age: 18,
height: 1.88
})
function changeInfoName(payload) {
info.name = payload
}
// 使用readOnly包裹info
const roInfo = readonly(info)
function changeRoInfoName(payload) {
info.name = payload
}
return {
info,
changeInfoName,
roInfo,
changeRoInfoName
}
}
}
</script>
<style scoped>
</style>
showinfo.vue
<template>
<div>
<h2>ShowInfo: {{ info }}</h2>
<!-- 代码没有错误, 但是违背规范(单项数据流) -->
<button @click="info.name = 'kobe'">ShowInfo按钮</button>
<!-- 正确的做法: 符合单项数据流-->
<button @click="showInfobtnClick">ShowInfo按钮</button>
<hr>
<!-- 使用readonly的数据 -->
<h2>ShowInfo: {{ roInfo }}</h2>
<!-- 代码就会无效(报警告) -->
<!-- <button @click="roInfo.name = 'james'">ShowInfo按钮</button> -->
<!-- 正确的做法 -->
<button @click="roInfoBtnClick">roInfo按钮</button>
</div>
</template>
<script>
export default {
props: {
// reactive数据
info: {
type: Object,
default: () => ({})
},
// readonly数据
roInfo: {
type: Object,
default: () => ({})
}
},
emits: ["changeInfoName", "changeRoInfoName"],
setup(props, context) {
function showInfobtnClick() {
context.emit("changeInfoName", "kobe")
}
function roInfoBtnClick() {
context.emit("changeRoInfoName", "james")
}
return {
showInfobtnClick,
roInfoBtnClick
}
}
}
</script>
<style scoped>
</style>
当readonly后,就算是父组件本身也无法修改如上代码的roInfo,但是是可以通过原始info修改的。
方法补充(了解)
什么叫shallow呢,就是浅层,shallowReactive就是浅层响应,如上图代码,当firend内的name属性变化,那么浅层响应就不会被修改。
toRefs函数
作用:如下当我们使用reactive函数后,在template中每次都需要通过info.name,info.age等等来取值,有的人想直接写name和age怎么办呢?
答:我们可以将此对象解构
出现问题:解构后,数据会变成普通数据,没有响应式的功能
解决:使用toRef函数再进行解构。
<template>
<div>
<h2>info: {{ name }} - {{ age }} - {{ height }}</h2>
<button @click="age++">修改age</button>
<button @click="height = 1.89">修改height</button>
</div>
</template>
<script>
import { reactive, toRefs, toRef } from 'vue'
export default {
setup() {
const info = reactive({
name: "why",
age: 18,
height: 1.88
})
// reactive被解构后会变成普通的值, 失去响应式
//多个解构
const { name, age } = toRefs(info)
//单个解构
const height = toRef(info, "height")
return {
name,
age,
height
}
}
}
</script>
<style scoped>
</style>
为什么setup函数内无法使用this?
所以并不是原先官方文档说的setup之前,data和computed等没有被做解析,而是:
它内部源码,没有给setup绑定this,原先的optionsApi的methods,computed什么的都通过appy和bind等绑定了this。
问题:没有this,那我如何this.$emit呢?
setup(props,context)里有两个默认参数,第一个就是父组件传递进来的数据,第二个就包含了: