Article Directory
- Vue3 composition api
-
- Create a Vue instance
- Vue.use principle
- setup function
- responsive data
- Computed property computed function
- A watch function that listens to responsive data
-
- Writing review of vue2
- Monitor computed property computed
- Listen to the getter function
- Listen to the properties defined by reactive
- Listen to arrays from multiple sources
- Listen to props attribute
- Listener watchEffect()
- Watch the DOM in the callback | watchPostEffect()
- Destroy the listener manually
Vue3 composition api
Create a Vue instance
- Create a Vue application instance
createApp
method - Mount application instance
.mount()
Each Vue application createApp
creates a new Vue application instance through the function
createApp()
: create an application instance
- The parameter is the root component object, which is used to configure the root component. This component is used as the starting point for rendering when the app is mounted.
mount
An application instance object with methods is returned .- Two tasks are completed inside the function ① create
app
an application instance ② rewriteapp.mount
the method
import {
createApp } from 'vue'
import App from'./App.vue' //引入根组件
//const app = createApp({
/* 根组件选项 */
//})
const app = createApp(App)
app.mount('#app')//将ID为app的节点挂载到Vue上
/*
vue2 写法
import Vue from 'vue';
new Vue({
render: h => h(App)
}).$mount('#app')
*/
Vue.use principle
Function: by Vue.use()
installing the plug-in
Vue.use()
The method passes at least one parameter, and the parameter type must be Object or Function.- If it is an Object, the Object needs to define an install method.
- If it is Function, this function is regarded as the install method.
Vue.use()
Execution is equivalent to executing the install method. If the same plugin is called multiple times, the plugin will only be installed once.
1. The above app is an instance of Vue, and the usage of app.use() is equivalent to Vue.use.
2. The first parameter is the plugin itself, and the optional second parameter is the option to be passed to the plugin.
setup function
setup()
It is used to cooperate with the combined API to provide users with a place to build combined logic, create responsive data, create general functions, register declaration cycle hooks and other capabilities.
- There are two return values
- Returns a function that will be used as the component's
render
function - Returns an object that exposes the data contained in the object to the template. The properties and methods in the object can be used directly in the template.
- Returns a function that will be used as the component's
- The parameter is
(props,context)
- The first parameter accepts a reactive
props
, whichprops
points to an externalprops
. If not definedprops选项
,setup
the first argument in will beundifined
.
- The second parameter provides a context objectcontext
, context replaces this as the context, butcontext
there are onlyemit
,attrs
, andslots
.
- The first parameter accepts a reactive
illustrate
- setup cannot be an async function, because the return value is not a return object, but a promise, and the template cannot see the properties in the promise object
- In the entire life cycle,
setup函数
it will only be mounted once.beforeCreate
Execute once before, yesthis
(undefined
the timing of the setup call is executed before the props are parsed and the component instance is created), sosetup
the component instance cannot be obtained. - This way of writing will automatically expose all top-level variables and functions to the template (template)
//返回一个模板
<template>
{
{
name}}
{
{
say()}}
</template>
<script>
export default {
name: 'App',
setup() {
//这里定义的数据不是响应式数据
//数据
let name="ranan";
//方法
function say() {
console.log(`hello${
name}`);
}
return {
name,say}
}
}
</script>
//返回一个渲染函数
<template></template>
<script>
import {
h} from 'vue' //createElement函数
export default {
name: 'App',
setup() {
//渲染函数要把h函数调用的返回值返回
//return ()=>{return h('h1','ranan')}
return ()=> h('h1','ranan')
}
}
</script>
script setup
In Vue3.2 (vue2.7 is also supported), you only need to script
add setup
the attribute to the tag
Explanation
1. The context in which the component code runs during compilation is in setup()
the function
2. No need return
, it template
can be used directly in .
//语法糖
<script setup="props, context" lang="ts">
context.attrs
context.slots
context.emit
<script>
//同时支持结构语法
<script setup="props, { emit }" lang="ts">
<script>
3. In script setup
, the imported components can be used directly without components
registration, and the name of the current component cannot be specified, and the file name will automatically be the main one , that is, there is no need to write the name attribute.
<template>
<HelloWorld />
</template>
<script setup>
import HelloWorld from "./components/HelloWorld.vue";
</script>
script setup specifies the name of the current component
Method 1: Modify the file name, file name = component name
Method 2: Create a script tag at the same level as script setup, and throw name in the tag
<script setup lang="ts">
</script>
<script lang="ts">
export default {
name: 'app-viewer'
}
Method 3: Use the plug-in unplugin-vue-define-options
plug-in installation method
responsive data
ref()
make data responsiveshallowRef()
It only handles the responsive processing of basic data types, not the responsive processing of objects.reactive()
The deep-level object responsiveness defined is based on the internalProxy
implementation, and the internal data of the source object is manipulated through the proxy object.shallowReactive()
Create a shallow response object (one layer response)
ref function data hijack defineProperty
ref()
Make the data responsive, wrap the value into RefImpl
a reference object ( Ref
object) and return
Create an object, set the value attribute of the object as the incoming parameter, then perform responsive processing on the object, and finally return the responsive object
- The principle of ref responsiveness is to use data hijacking (first layer) :
defineProperty
in usegetter
,setter
- The acquisition of data uses
属性名.value
acquisition, but the attribute name can be used directly in the template (automatically unwrapped), and the template will automatically属性名.value
<script setup lang="ts">
import {
ref} from 'vue'
let count = ref(0) //生成一个0的响应式数据
console.log(count.value) //RefImpl{value:0....}
console.log(count) //0
count=10 //对0重新赋值,现在count不再是响应式数据
</script>
<template>
<div>{
{
count }}</div>
</template>
The parameter of the ref function is an object
const 返回值obj = ref(参数对象)
The return value obj itself is still a RefImpl object, but obj.value
what is returned is Proxy
a proxy object for the parameter object, and the source object is indirectly manipulated through the operation of the proxy object.
<script setup lang="ts">
import {
ref} from 'vue'
/*
count是响应式的,name也是响应式的
const tmp = {name:ref("ranran")] name是响应式的,tmp不是响应式的
*/
const count = ref({
name:"ranran"})
console.log(count) //返回一个RefImpl对象,对象的value值为传入的参数{value:{name:"ranran"}}
console.log(count.value) //Proxy(Object) {name: 'ranran'}
console.log(count.name) //注意这个是访问不到的,因为ref函数是创建一个对象,对象的value属性设置为传入的参数,然后对对象做响应式处理,最后返回响应式对象
</script>
<template>
<div>{
{
count }}</div>
</template>
Details of automatic unpacking
template
Automatic unpacking problem in tags: automatic unpacking only unpacks top-level attributes顶层属性.value.xxx
const obj = ref({
name:"ranran"
})
const obj2 = {
name:ref("biubiu")
}
</script>
<template>
<div>
//自动解包obj.value.name
<div>{
{
obj.name }}</div>
//obj2不是响应式数据,所以没有自动解包。错误写法
<div>{
{
obj2.name }}</div>
//正确写法
<div>{
{
obj2.name.value}}</div>
</div>
</template>
The source code of the ref function
function ref(value) {
return createRef(value, false); //创建ref对象,第一个参数时需要响应的数据,第二个参数是是否浅拷贝
}
function createRef(rawValue, shallow) {
if (isRef(rawValue)) {
return rawValue;
}
return new RefImpl(rawValue, shallow);
}
class RefImpl {
constructor(value, _shallow) {
this._shallow = _shallow;
this.dep = undefined;
this.__v_isRef = true;
this._rawValue = _shallow ? value : toRaw(value);
this._value = _shallow ? value : convert(value);
}
get value() {
trackRefValue(this);
return this._value;
}
set value(newVal) {
newVal = this._shallow ? newVal : toRaw(newVal);
if (hasChanged(newVal, this._rawValue)) {
this._rawValue = newVal;
this._value = this._shallow ? newVal : convert(newVal);
triggerRefValue(this, newVal);
}
}
}
unref()
If the argument is a ref, returns the internal value, otherwise returns the argument itself. This is val = isRef(val) ? val.value : val
a syntactic sugar function for .
Usage scenario: when a value may be ref or a value other than ref
reactive function data proxy Proxy
const 代理对象 = reactive(源对象)
: Define a responsive proxy for an object , accept an object (array), and return a Proxy instance object.
reactive()
The defined responsive data is deep-level , internally based onProxy
implementation, and the internal data of the source object is manipulated through the proxy object.shallowReactive()
Create a shallow response object (one layer response)
<script setup lang="ts">
import {
reactive} from 'vue'
const stu = reactive({
name:"ranran"})
console.log(stu)
/*
{
"name": "ranran"
}
*/
</script>
toRef(obj,prop) creates a ref object
Function: toRef(响应式对象,该对象的属性)
create one ref对象
, 该ref对象
whose value
value points to a property in the parameter object (if the value of the ref object changes, the property in the parameter object will also change, and vice versa)
Description: The essence is a reference, which is associated with the original
data Scenario: To provide a property in the responsive object for external use alone
illustrate
- For the properties of a responsive object , if it is used for a normal object (non-responsive object), the returned result is not responsive.
toRef返回值
and对象 Object
Both maintain a reference relationship (one changes and the other changes)
toRefs(obj) creates multiple ref objects
toRefs(obj)
: Returns an ordinary object consistent with the parameter, except that the value of the attribute becomes a ref object
illustrate
toRefs
Does not take effect for newly added attributes- For all properties of the entire object, the goal is to convert the reactive object (reactive package) into a normal object.
return{
...toRefs(person)
}
1.
ref
The essence is copying, modifying the responsive data will not affect the original data, the
toRef、toRefs
essence of the view will be updated is reference, modifying the responsive data will affect the original data, the view will not be updated
2.toRef、toRefs
Do not create responsive, but It is a continuation response.
Side effect function effect()
When a piece of data changes, effect
the function is automatically re-executed, and we call the data reactive. (It will be executed automatically when the responsive data changes effect()
) The execution of
side-effect functions effect()
will directly or indirectly affect the execution of other functions.
//假设obj是一个响应式数据
const obj = {
text:'xxx'}
function effect(){
//effect函数
console.log(obj.text);
}
//修改响应式数据
obj.text = 'yyy'
//手动模拟
effect()//响应式数据发生变化,自动执行effect()
reactive responsive principle
In essence, the reading and writing of data objects is proxied through Proxy
- When we access the proxy object, the getter will be triggered to perform dependency collection
track()
:track()
Collect dependencies, each property of the object has its own , collectdep
all the properties that depend on this property , and put them in.effect函数
dep
- When the data is modified, the setter dispatch notification will be triggered.
trigger()
:trigger()
Notification dependencies. After the dependencies are collected, as soon as the variable changes, all executions that depend on the variable intrigger()
the notification will be executed to realize the update of the dependent variable.dep
effect()
- Each attribute of the object has its own dep, and all the attributes that depend on this attribute are
effect函数
collected and placeddep
in the . - Each object will create a
Map
corresponding relationship between each attribute and dep, the key is the attribute name, and the value is the dep of the attribute (using Set to store). - Use
WeakMap
to store multiple objectsMap
Proxy-Reflect
Implement automatic collection and trigger dependenciestrack-trigger函数
//reactive 将对象变成响应式的
function reactive(target) {
const handler = {
get(target, key, receiver) {
track(receiver, key) // 访问时收集依赖
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver)
trigger(receiver, key) // 设值时自动通知更新
}
}
return new Proxy(target, handler)
}
The comparison between reactive and ref
reactive | ref | |
---|---|---|
define data | object type data | If the basic type of data defines an object, .value will use reactive to convert the object into a proxy object |
principle | Proxy implements responsive (data proxy) through Reflect to manipulate the properties inside the source object |
Realize responsiveness (data hijacking) through get and set of Object.defineProperty() |
use | No need to use .value | The operation data needs .value, and the automatic unpacking and reading in the template does not need .value |
Computed property computed function
The computed attribute is a computed attribute in Vue3 响应式
(returning a ref object), which automatically updates its own value according to changes in other responsive data (does not detect updates to non-responsive data).
import {
computed} from 'vue'
setup(){
//计算属性fullName -简写内部是函数形式,只符合被读取的情况
let fullName = computed(()=>{
return person
})
//计算属性-完整写法
let fullName = computed({
get(){
},
set(val){
}
})
}
The principle of the computed attribute is to use a getter function and a setter function to achieve, and the dependent data of computed (data that monitors changes) needs to be responsive
A watch function that listens to responsive data
watch()
Used to listen to a specific data source and perform side effects in the callback function. By default the callback is only executed when the listened source data changes.
watch(data,function(),[option])
- Monitored Reactive Data
ref
object- computed property
getter
Function: It can be simply understood as a function to obtain data, which is an operation that returns a valuereactive
The defined attribute willdeep:true
force the open- Listen to arrays from multiple sources
- The callback function for this data binding
- Configuration parameters of vue2: support deep, immediate and flush options.
Writing review of vue2
illustrate
- When the monitored property changes,
handler(newVal,oldVal)
the function is called, and it is not called during initialization (can be set) - Can monitor attributes in data and computed
- The watch in Vue does not monitor the change of the internal value of the object by default (one layer)
- Configure deep:true to detect internal value changes in objects (multi-layer)
//写法1
new Vue({
el:'#root',
data:{
firstName:'ran',
lastName:'an'
},
watch:{
isHot:{
//固定配置
immediate:false; //默认false,初始化时调用handler函数
//当监视的属性发生变化时,handler调用
handler(newVal,oldVal){
}
}
}
});
//写法2
vm.$watch('isHot',{
配置信息})
//简写
watch:{
isHot(newVal,oldVal){
}
}
vm.$watch('isHot',function(newVal,oldVal){
//handler函数})
Monitor computed property computed
import {
ref,computed,watch} from 'vue'
const message = ref("ranran");
const newMessage = computed(() => {
return message.value;
});
watch(newMessage, (newValue, oldValue) => {
});
Listen to the getter function
const x1 = ref(12);
const x2 = ref(13);
watch(
() => x1.value + x2.value,//类似计算属性
(newValue, oldValue) => {
}
);
Listen to the properties defined by reactive
Listening reactive
to the defined properties will force deep:true
deep monitoring to be enabled (automatically create a deep listener, and the deep configuration is invalid), and any changes in the properties of the responsive object will trigger the callback function in the monitoring function.
Unable to get oldValue correctly, the values of oldValue and newValue are the same. Because the object is a reference type, even if the properties inside have changed, the address of the object has not changed, and oldValue and newValue point to the same address.
import {
reactive,watch} from 'vue'
let person= reactive({
name:"ranna",
age:18,
job:{
j1:{
salary:20
}
}
})
watch(person,(newValue,oldValue)=>{
})
watch cannot directly monitor the properties of the responsive object
1. watch cannot directly monitor the properties of responsive objects, which is equivalent to watch
passing a non-responsive number directly to , but watch
can only monitor responsive data.
//错误写法
const number = reactive({
count: 0 });
const countAdd = () => {
number.count++;
};
watch(number.count, (newValue, oldValue) => {
});
Solution: Use getter
the form of function, in this case you can getoldValue
watch(
() => number.count,//返回的是基本数据类型
(newValue, oldValue) => {
}
);
2. Special case: Proxy is automatic depth, Object depth on demand
If we use getter()
the form of returning a responsive object, the callback function of the watch will not be triggered if the property value of the responsive object changes.
//自动开启deep
watch(person.job,(newValue,oldValue)=>{
})
watch(()=>person.job,(newValue,oldValue)=>{
},{
deep:true})//返回的是一个obj,需要手动开启deep
It is recommended getter()
to listen to a certain property in the responsive object
Listen to arrays from multiple sources
watch
Arrays can also be monitored, provided that the array contains responsive data.
let sum = ref(0)
let msg= ref("hello")
watch([sum,msg],(newvalue,oldValue)=>{
//此时newvalue和oldValue都是数组,里面的顺序和第一个参数的顺序一致
})
Listen to props attribute
Listen to the entire props
<script setup>
import {
ref, watch } from 'vue';
const props = defineProps({
listData: {
type: Array,
default: [],
}
});
const childList = ref([])
watch(props, (nweProps)=>{
childList.value = nweProps.listData
})
</script>
Listen to specific properties in props
<script setup>
import {
ref} from 'vue';
const appearState = ref(false);
const props = defineProps({
show: {
type: Boolean,
default: () => false,
},
});
watch(
() => props.show,
(newVal) => {
appearState.value = newVal;
},
);
Listener watchEffect()
watchEffect()
It is also a listener, the first parameter is the callback function, and the second parameter is the configuration object, which will be executed when the function is initialized (from scratch). In the callback function, the response attribute is automatically monitored. When the response data in the callback function changes, the callback function will be executed immediately.
- The routine of watch is: not only the attribute of monitoring, but also the callback of monitoring should be specified
- The routine of watchEffect is: no need to specify which attribute to monitor, which attribute is used in the monitoring callback, and which attribute to monitor. The callback function is executed when the monitored data changes.
//一上来就会执行
watchEffect(()=>{
})
Watch the DOM in the callback | watchPostEffect()
Get the DOM in the callback function of the listener, and the default is to get the DOM before updating.
Method 1: Configuration options
If you want to get the updated DOM in the callback function, you only need to pass one more parameter option to the listener flush: 'post'
.
watch(source, callback, {
flush: 'post'
})
watchEffect(callback, {
flush: 'post'
})
Method 2: watchPostEffect
watchPostEffect(() => {
/* 在 Vue 更新后执行 */
})
Destroy the listener manually
Usually after a component is destroyed or uninstalled, the listener will also stop. However, in some special cases, the listener still exists and needs to be closed manually, otherwise it is easy to cause memory leaks.
//案例
<script setup>
import {
watchEffect } from 'vue'
// 它会自动停止
watchEffect(() => {
})
// 这个时候监听器没有与当前组件绑定,所以即使组件销毁了,监听器依然存在。
setTimeout(() => {
watchEffect(() => {
})
}, 100)
</script>
Solution: Use a variable to receive the return value of the listener function, and the return value is a function that closes the current listener.
const unwatch = watchEffect(() => {
})
// ...当该侦听器不再需要时
unwatch()