创建应用实例
vue3.0创建vue实例不再通过new Vue()
方式创建,而是通过createApp
工厂函数创建。
该应用实例是用来在应用中注册“全局”组件。
应用实例暴露的大多数方法都会返回该同一实例,允许链式。
createApp
需要引入才能使用。
import { createApp } from 'vue'
import App from './App.vue'
import son from './components/son.vue'
createApp(App).component('son', son).mount('#app')
setup([props],[context])
setup
是vue3新增加的配置项,在模版中使用的数据和方法都要在此方法中返回才能使用。
setup执行时间在beforeCreate()
生命周期之前。
setup有两种返回结果:
- 返回对象,只有在该对象中返回的数据和方法才能在模版中使用。
- 返回一个渲染函数。它会替代模版作为渲染界面结果。
<template>
<h1>123445</h1>
<h1>{{ name }}</h1>
<button @click="changeVal">点击</button>
</template>
<script>
import { ref, h } from 'vue'
export default {
setup() {
let name = ref('1')
console.log(name)
function changeVal(){}
return { name,changeVal }
// return () => h('h1', { style: { color: 'red' } }, '这是渲数')
}
}
参数
setup接受两个参数。
props
props
是个响应式对象。不可以使用解构语法,会丢失响应式。
该对象接受在props配置项中定义的所有内容。
export default {
props: ['school', 'age', 'name'],
setup(props) {
console.log(props)
}
}
// Proxy {school: undefined, age: undefined, name: undefined}
context
context
是个普通对象。可以使用解构语法。
该对象有如下属性:
attrs:(对象)
接受未在props配置项定义,但是在组件传过来的属性。(等同于vue2中this.$attrs
)emit:(函数)
用于分发自定义事件,需要在emits配置项中定义该事件。(等同于vue2中this.$emit
)。否则会在控制台出现警告。slots(对象)
: 接受组件定义的插槽内容。(等同于vue2中this.$slots
)expose:(函数)
用于控制哪些内容会明确地公开暴露给组件使用者。
// 父组件
setup() {
let child = ref(null)
onMounted(() => {
console.log(child.value.n) //undefined
console.log(child.value.n1) //undefined
console.log(child.value.n2) // Proxy {value: "子组件3"}
})
return { child }
}
// 子组件
setup(props, { expose }) {
let n = ref('子组件')
let n1 = ref('子组件1')
let n2 = reactive({ value: '子组件3' })
expose({ n2 })
return { n, n1, n2 }
}
生命周期
使用如下api需要单独引入。
在setup中通过在生命周期钩子前面加上 “on” 来访问组件的生命周期钩子。
这些函数接受一个回调函数。当钩子被组件调用时将会被执行。
destroyed/beforeDestroy 改为了unmounted/beforeUnmount。
setup() {
onMounted(()=>{
// 做一些事情
})
return { }
}
对应关系: | |
---|---|
选项式 API | setup |
beforeCreate | - |
created | - |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
updated | onUpdated |
beforeUnmount | onBeforeUnmount |
unmounted | onUnmounted |
activated | onActivated |
deactivated | onDeactivated |
api
使用以下api需要单独引入。
ref
let variable = ref(initVal)
创建一个响应式的数据。
- 在setup中操作数据要使用
variable.value
形式。 - 在模版中则可以直接使用。
<h1>{{ variable }}</h1>
。 - 如果创建的值为对象类型,在内部会使用
reactive
处理。
setup() {
let name = ref(1)
function changeVal() {
name.value++
}
return { name, changeVal }
}
在setup中使用模版引用,只会在初始渲染(mounted)之后获得赋值。
setup() {
let root = ref(null)
onBeforeMount(() => {
console.log(root.value) // null
})
onMounted(() => {
console.log(root.value) //<h3 ref="root">159</h3>
})
return { root }
}
reactive
let variable = reactive(initVal)
创建对象
类型的响应式数据。
- 使用
reactive
创建的响应式数据无需使用variable .value来获取数据。可以直接访问。 reactive
不能用来创建基本类型的响应式数据。控制台会提示:value cannot be made reactive:
。应该用ref
去创建基本类型的响应式数据。- reactive的响应是深层次的,可以监听到属性的添加和删除。
- 使用reactive创建的数组类型的响应式数据,我们使用下标修改数据,在vue3中也是可以监听到的。(在vue2中这样是不能监听到的)。
setup() {
let re = reactive({ name: '李四', age: 123 })
function add() {
re.age++
re.job = '1'
}
return { re, add }
}
shallowReactive
let variable = shallowReactive(initVal)
创建对象类型响应式数据。它的响应式是浅层的,不执行嵌套对象的深层响应式转换 (暴露原始值)。
setup() {
let person = shallowReactive({
name: '李四',
age: 123,
job: { jb2: { slary: 20 } }
})
function change1() {
person.job.jb2.slary += 1 // 页面不更新
}
function change() {
person.name += '-' // 页面更新
}
return { person, change1 }
}
readonly
接受一个对象 (响应式或纯对象) 或 ref并返回原始对象的只读代理。只读代理是深层的:任何被访问的嵌套 property 也是只读的。
setup(){
let person = reactive({ name: 'lisi', jb: { jb1: { val: 1 } } })
function change() {
person.jb.jb1.val++ // Set operation on key "val" failed: target is readonly
}
person = readonly(person)
return {person,change}
}
shallowReadonly
接受一个对象 (响应式或纯对象) 或 ref并返回原始对象的只读代理。只读代理是浅层的。
setup(){
let person = reactive({ name: 'lisi', jb: { jb1: { val: 1 } } })
function change() {
person.jb.jb1.val++ //页面更新
}
function changeName() {
person.name+='-' //Set operation on key "name" failed: target is readonly
}
person = readonly(person)
return {person,change,changeName}
}
computed
创建计算属性。有两种定义方式(同vue2)。
computed返回的是个ref对象。
-
let variable = computed(
{ get(){},set(value) { }}
) --- 完整接受一个具有
get
和set
函数的对象,用来创建可写的 ref 对象。 -
let variable =
computed(函数)
--- 简写相当于只有getter。 返回一个不可变的响应式 ref 对象。
watch
侦听属性。
watch(val,()=>{},[配置项])
watch 需要侦听特定的数据源,并在单独的回调函数中执行副作用。默认情况下,它也是惰性的——即回调仅在侦听源发生变化时被调用。
1.当watch监听的为ref类型定义的响应式数据时:
- watch(
ref
,(newV,oldV)=>{ 处理内容 }) // 单个ref - watch(
[ref,ref]
,(newV,oldV)=>{ 处理内容 }) // 监听多个属性
2.当watch监听的为reactive定义的响应式数据时:
-
watch(
reactive
,(newV,oldV)=>{ 处理内容 })当监听reactive定义的对象时总是深度监听,配置deep无效。且oldV总是等于newV。
-
watch(
()=>reactive.prop
,(newV,oldV)=>{ 处理内容 })监听reactive响应式数据的某个属性时,必须使用函数返回该属性。
-
watch(
[()=>reactive.prop,()=>reactive.prop]
,(newV,oldV)=>{ 处理内容 })监听多个属性
watchEffect
watchEffect(()=>{})
立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。
与computed
大体相同,但是watchEffect关注的是过程
,computed关注的是结果
。
toRefs
let val = toRef(响应式对象)
将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的ref。可以使用...
语法,而且不会破坏响应式。
setup() {
let person = reactive({ name: 'lisi', age: 23 })
let p = toRefs(person)
return { ...p }
}
toRef
let val = toRef(响应式对象,prop)
根据响应式对象的某个属性,创建一个 ref
,ref 可以被传递。它会保持对其源 property 的响应式连接。
setup() {
let person = reactive({ name: 'lisi', age: 23 })
return { u: toRef(person,'name') }
}
toRaw
let val = toRaw(对象)
返回 reactive 或 readonly代理的原始对象。
setup() {
let person = reactive({ name: 'lisi', age: 23 })
let p = toRaw(person)
console.log(p) // {name: "lisi", age: 23}
return { person }
}
markRaw
let val = markRaw(对象)
标记一个对象,使其永远不会转换为 proxy。返回对象本身。
setup() {
let val = markRaw({ name: 'wang' })
let p = reactive(val)
console.log(isReactive(p)) // fasle
return {}
}