setup
1、理解:vue3.0 中一个新的配置项,值为一个函数
2、setup
是所有 Composition API(组合API) “表演的舞台”
3、组件中所用到的:数据、方法等等,均要配置在setup
中
4、setup函数的两种返回值:
----①、若返回一个对象,则对象中的属性、方法,在模板中均可以直接使用(重点关注! )
----②、若返回一个渲染函数:则可以自定义渲染内容。(了解)
5、注意点:
----①尽量不要与Vue2.x配置混用
-------Vue2.x配置(data、methos、computed…)中可以访问到setup
中的属性、方法。但在setup
中不能访问到 Vue2.x 配置(data、methos、computed…)。如果有重名, setup优先,
----②setup
不能是一个async
函数,因为返回值不再是return
的对象,而是promise
,模板看不到return
对象中的属性(后期也可以返回一个 Promise 实例,但需要 Suspense和异步组件的配合)
我们来修改上一节创建的 vue3 项目,修改 App.vue
<template><h1>一个人的信息</h1><h3>姓名:{{ name }}</h3><h3>年龄:{{ age }}</h3><button@click="sayHello">说话</button></template><script>exportdefault{name:'App',setup(){//数据let name="张三"let age=18functionsayHello(){alert(`我叫${name},我${age}岁了`)}//返回一个对象return{name: name,//触发简写形式
age,
sayHello}}}</script>
......
运行:
测试下上面说的几点中 4.2 返回渲染函数的时候
<script>import{h}from'vue'exportdefault{name:'App',setup(){return()=>{returnh("h1","三里屯小学")}}}</script>
ref 函数
作用:定义一个响应式的数据
语法:const xxx = ref(initvalue)
。创建一个包含响应式数据的引用对象
(reference对象,简称ref对象)
。JS中操作数据:xxx.value
。模板中读取数据:不需要.value
,直接:<div>{{xxx} }</div>
备注:
。接收的数据可以是:基本类型、也可以是对象类型
。基本类型的数据:响应式依然是靠0bject.defineProperty()
的get
与set
完成的
。对象类型的数据:内部“求助”了 Vue3.0 中的一个新函数——reactive
函数
<template><h1>一个人的信息</h1><h3>姓名:{{ name }}</h3><h3>年龄:{{ age }}</h3><h3>职业:{{ job.type }}</h3><h3>薪水:{{ job.salary }}</h3><button@click="changeInfo">修改人的信息</button></template><script>import{ref}from'vue'exportdefault{name:'App',setup(){//数据let name=ref("张三")let age=ref(18)let job=ref({type:'前端工程师',salary:'30k'})functionchangeInfo(){
name.value="李四"
age.value=25
job.value.type="UI设计师"
job.value.salary="60k"}return{
name,
age,
job,
changeInfo}}}</script>
被 ref 包裹的 name 变成了 refimpl 对象,可以打印看下
RefImpl 就是引用对象实例对象,拆分成两个单词:reference
:引用implement
:实现
可以看到里边有 value,我们用鼠标点开...
,值就是我们定义的值。所以在 js 中操作的时候,我们需要.value
来取值
reactive 函数
作用:定义一个对象类型的响应式数据(基本类型不要用它,要用ref
函数)
语法:const 代理对象 = reactive(源对象)
接收一个对象(或数组),返回一个代理对象(proxy的实例对象,简称proxy对象)
reactive
定义的响应式数据是"深层次的"
内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作
<template><h1>一个人的信息</h1><h3>职业:{{ job.type }}</h3><h3>薪水:{{ job.salary }}</h3><h3>爱好:{{ hobby }}</h3><h3>测试数据的值:{{ job.a.b.c }}</h3><button@click="changeInfo">修改人的信息</button></template><script>import{reactive}from'vue'exportdefault{name:'App',setup(){//数据let job=reactive({type:'前端工程师',salary:'30k',a:{b:{c:666}}})let hobby=reactive(['抽烟','喝酒','烫头'])//counts changeInfo = ()=>{...}functionchangeInfo(){
job.type="UI设计师"
job.salary="60k"
job.a.b.c=999
hobby[0]='学习'}return{
job,
hobby,
changeInfo}}}</script>
可以看到使用 reactive 后不用再使用.value
来取值,同时,可以修改深层次的数据,因为我们把 a.b.c 的值改了。而且数组的值也可以改
由于不能处理基本类型数据,如果想处理上一个例子中的姓名、年龄等数据可以将数据都放到一个数组中
<template><h1>一个人的信息</h1><h3>姓名:{{ person.name }}</h3><h3>年龄:{{ person.age }}</h3><h3>职业:{{ person.job.type }}</h3><h3>薪水:{{ person.job.salary }}</h3><h3>爱好:{{ person.hobby }}</h3><h3>测试数据的值:{{ person.job.a.b.c }}</h3><button@click="changeInfo">修改人的信息</button></template><script>import{reactive}from'vue'exportdefault{name:'App',setup(){let person=reactive({name:'张三',age:18,job:{type:'前端工程师',salary:'30k',a:{b:{c:666}}},hobby:['抽烟','喝酒','烫头']})functionchangeInfo(){
person.name="李四"
person.age=25
person.job.type="UI设计师"
person.job.salary="60k"
person.job.a.b.c=999
person.hobby[0]='学习'}return{
person,
changeInfo}}}</script>
reactive对比ref
从定义数据角度对比
。ref
用来定义:基本类型教据
。reactive
用来定义:对象〔或数组)类型数据
。备注:ref
也可以用来定义对象((或数组)类型数据,它内部会自动通过reactive
转为代理对象
从原理角度对比
。ref
通过object.defineProperty()
的 get 与 set 来实现响应式(数据劫持)
。reactive
通过使用Proxy
来实现响应式(数据劫持),并通过Reflect
操作源对象内部的数据
从使用角度对比
。ref
定义的数据:操作数据需要.value
,读取数据时模板中直接读取不需要.value
。reactive
定义的数据:操f作数据与读取数据:不需要.value
setup 两个注意点
setup 执行的时机
。在beforeCreate
之前执行一次,this
是undefined
setup 的参数
。props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性
。context:上下文对象
-------attrs:值为对象,包含:组件外部传递过来,但没有在 props 配置中声明的属性,相当于 this.$attrs
-------slots:收到的插槽内容,相当于this.$slots
-------emit:分发自定义事件的函数,相当于this.$cmit
参数props
我们来实际打印下,在 App 中引入 Demo 组件并传值
<template><div><Demomsg="hello"/></div></template><script>import Demofrom'./components/Demo'exportdefault{name:'App',components:{Demo}}</script>
Demo 组件中接收,并在 setup 中打印 props
<template><h2>{{msg}}</h2></template><script>exportdefault{name:'HelloWorld',props:{msg: String},setup(props){
console.log(props);}}</script>
参数context
其中 setup 还能接收一个参数,我们来打印下
setup(props,context){
console.log(context);
}
1、其中attrs
,如果 App 给 Demo 传值了,但没有使用 props 接收,那么值就会存在 attrs 中。跟Vue2 中的 $attrs 的一样
2、看下emit
我们先给 Demo 传递一个 hello 事件
<template><div><Demo@hello="showHello"msg="hello"/></div></template><script>import Demofrom'./components/Demo'exportdefault{name:'App',components:{Demo},setup(){functionshowHello(value){
console.log(`触发hello事件,收到了参数是:${value}`);}return{
showHello}}}</script>
Demo 中接收
<template>
......<button@click="test">测试hello事件</button></template><script>exportdefault{......emits:['hello'],setup(props,context){......functiontest(){
context.emit("hello",666)}return{
test}}}</script>
3、其中slot
App 中使用插槽
<template><div><Demo@hello="showHello"msg="hello"><templatev-slot:bottom><span>你好</span></template></Demo></div></template>
Demo 中打印下context.slots
<template><h2>{{msg}}</h2><button@click="test">测试hello事件</button><slotname="bottom"></slot></template><script>exportdefault{......setup(props,context){
console.log(context.slots);......}}</script>