ホームページ  >  記事  >  ウェブフロントエンド  >  Vue3 の応答メカニズムの詳細な分析を提供する記事

Vue3 の応答メカニズムの詳細な分析を提供する記事

青灯夜游
青灯夜游転載
2022-09-19 20:13:141985ブラウズ

Vue3 の応答メカニズムの詳細な分析を提供する記事

今日は、Vue 3 のレスポンシブ メカニズムについて詳しく説明します。今日の内容を学習すると、レスポンシブ メカニズムについてさらに深く理解できると思います。 ; コード例とも組み合わせて、レスポンシブ メカニズムの高度な使い方をマスターできるように、正式に学習を始めましょう。 [関連する推奨事項: vuejs ビデオ チュートリアル ]

応答性とは

応答性は常に Vue One の機能です関数の説明です。対照的に、JavaScript の変数には応答性の概念がありません。JavaScript を学習するときに最初に植え付けられる概念は、コードは上から下に実行されるということです。

以下のコードを見てみましょうコードの実行後、出力される 2 つの double の結果も 2 になります。コード内の count の値を変更しても、double の値はまったく変化しません

let count = 1
let double = count * 2
count = 2

double の値はcount の値に 2 を乗算した値に基づいて計算されます。count の変更に応じて double を変更したい場合は、count の値が変更されるたびに double

を再計算する必要があります。

たとえば、次のコードでは、最初に double を計算するロジックを関数にカプセル化し、カウントを変更した後、再度実行すると、最新の double 値が得られます。

let count = 1
// 计算过程封装成函数
let getDouble = n=>n*2 //箭头函数
let double = getDouble(count)
count = 2
// 重新计算double ,这里我们不能自动执行对double的计算
double = getDouble(count)

実際の開発 計算ロジックは非常に複雑になります。 double の計算よりも複雑ですが、関数にカプセル化して実行できます。次に考えなければならないのは、double の値を自動的に計算する方法です。

以下の図に示すように、getDouble 関数を自動的に実行させることができれば、JavaScript の何らかのメカニズムを使用して count をレイヤーでラップし、count が変更されるたびに double の値が同期的に更新され、倍数がカウントの変化に応じて自動的に変化するように、これが応答性の原型です。

Vue3 の応答メカニズムの詳細な分析を提供する記事


応答性の原理

何応答性の原理ですか? Vue では、defineProperty、Proxy、および value setter という 3 つの応答ソリューションが使用されています。まず Vue 2 の defineProperty API

ここで例を示します。次のコードでは、obj が使用する各オブジェクトを定義しますdefineProperty を使用して count 属性をプロキシします。このようにして、obj オブジェクトの value 属性をインターセプトし、count 属性を読み取るときに get 関数を実行し、count 属性を変更するときに set 関数を実行し、set 関数内でリセットします。 double

let getDouble = n=>n*2
let obj = {}
let count = 1
let double = getDouble(count)
Object.defineProperty(obj,'count',{
    get(){
        return count
    },
    set(val){
        count = val
        double = getDouble(val)
    }
})
console.log(double) // 打印2
obj.count = 2
console.log(double) // 打印4 有种自动变化的感觉

これにより、単純な応答関数を実現できます。コースの 4 番目のパートでは、より完全な応答システムを作成することもできます。

ただし、Property を定義する原則として、 Vue 2 での応答性の実装では、API の構文にもいくつかの欠陥があります。たとえば、次のコードでは、obj.count 属性を削除すると、set 関数は実行されず、double は以前の値のままになります。これが、Vue 2 では、データを削除する特別な関数 $delete が必要な理由です

delete obj.count
console.log(double) // doube还是4

Vue 3 の応答メカニズムは、プロキシという名前に関する限り、プロキシに基づいて実装されています, あなたも見ることができます これはプロキシの意味です プロキシの重要な意味は、Vue 2 の応答性の欠点を解決することです

# 次のコードを見てみましょう。プロキシを使用し、get、set、およびを使用します。 deleteProperty 関数は、オブジェクトの読み取り、変更、および削除の操作をプロキシし、応答性の高い関数を実現します。

let proxy = new Proxy(obj,{
    get : function (target,prop) {
        return target[prop]
    },
    set : function (target,prop,value) {
        target[prop] = value;
        if(prop==='count'){
            double = getDouble(value)
    }
},
deleteProperty(target,prop){
    delete target[prop]
    if(prop==='count'){
        double = NaN
    }
   }
})
console.log(obj.count,double)
proxy.count = 2
console.log(obj.count,double)
delete proxy.count
// 删除属性后,我们打印log时,输出的结果就会是 undefined NaN
console.log(obj.count,double)
ここから、プロキシによって実装された関数は次のようなものであることがわかります。 Vue 2のdefineProperyと同様にユーザーが利用することができ、データ変更時にset関数がトリガーされ、doubleを自動更新する機能を実現しています。さらに、Proxy は、definePropery のいくつかの欠陥も改善しました。たとえば、プロパティの削除を監視できます。

Proxy は、特定のプロパティではなくオブジェクトを監視するため、存在しないオブジェクトをプロキシするだけではありません。プロパティは、Map、Set などのより豊富なデータ構造のプロキシを行うこともでき、deleteProperty

を通じて削除操作のプロキシを実装することもできます。もちろん、プロキシを理解するのに役立つように、 double 関連も使用できます コードは実装用の set 関数と deleteProperty 関数に記述されています コースの後半では、より完全なカプセル化を行う方法を説明します。たとえば、次のコードでは、Vue 3 のリアクティブ関数を使用します。オブジェクトを応答性の高いデータに変換でき、Reactive は Proxy に基づいて実装されます。obj.count

を変更した後に watchEffect を使用してデータを出力することもできます。

import {reactive,computed,watchEffect} from 'vue'
let obj = reactive({
    count:1
})
let double = computed(()=>obj.count*2)
obj.count = 2
watchEffect(()=>{
    console.log('数据被修改了',obj.count,double.value)
})

有了 Proxy 后,响应式机制就比较完备了;但是在 Vue 3 中还有另一个响应式实现的逻辑,就是利用对象的 get 和 set 函数来进行监听,这种响应式的实现方式,只能拦截某一个属性的修改,这也是 Vue 3 中 ref 这个 API 的实现

在下面的代码中,我们拦截了 count 的 value 属性,并且拦截了 set 操作,也能实现类似的功能

let getDouble = n => n * 2
let _value = 1

double = getDouble(_value)
let count = {
    get value() {
        return _value
    },
    set value(val) {
        _value = val
        double = getDouble(_value)
    }
}

console.log(count.value,double)
count.value = 2
console.log(count.value,double)

三种实现原理的对比表格如下,帮助你理解三种响应式的区别

实现原理 defineProperty Proxy value setter
实际场景 Vue 2 响应式 Vue 3 reactive Vue 3 ref
优势 兼容性 基于proxy实现真正的拦截 实现简单
劣势 数组和属性删除等拦截不了 兼容不了 IE11 只拦截了 value 属性
实际应用 Vue 2 Vue 3 复杂数据结构 Vue 3 简单数据结构

定制响应式数据

简单入门响应式的原理后,接下来我们学习一下响应式数据在使用的时候的进阶方式;我们看下使用 <script setup></script> 重构之后的 todolist 的代码;这段代码使用 watchEffect,数据变化之后会把数据同步到 localStorage 之上,这样我们就实现了 todolist 和本地存储的同步

import { ref, watchEffect, computed } from "vue";
let title = ref("");
let todos = ref(JSON.parse(localStorage.getItem('todos')||'[]'));
watchEffect(()=>{
    localStorage.setItem('todos',JSON.stringify(todos.value))
})
function addTodo() {
    todos.value.push({
        title: title.value,
        done: false,
    });
    title.value = "";
}

更进一步,我们可以直接抽离一个 useStorage 函数,在响应式的基础之上,把任意数据响应式的变化同步到本地存储;我们先看下面的这段代码,ref 从本地存储中获取数据,封装成响应式并且返回,watchEffect 中做本地存储的同步,useStorage 这个函数可以抽离成一个文件,放在工具函数文件夹中

function useStorage(name, value=[]){
    let data = ref(JSON.parse(localStorage.getItem(name)||'[]'))
    watchEffect(()=>{
        localStorage.setItem(name,JSON.stringify(data.value))
    })
    return data
}

在项目中我们使用下面代码的写法,把 ref 变成 useStorage,这也是 Composition API 最大的优点,也就是可以任意拆分出独立的功能

let todos = useStorage('todos',[])
function addTodo() {
    ...code
}

现在,你应该已经学会了在 Vue 内部进阶地使用响应式机制,去封装独立的函数;在后续的实战应用中,我们也会经常对通用功能进行封装;如下图所示,我们可以把日常开发中用到的数据,无论是浏览器的本地存储,还是网络数据,都封装成响应式数据,统一使用响应式数据开发的模式;这样,我们开发项目的时候,只需要修改对应的数据就可以了

Vue3 の応答メカニズムの詳細な分析を提供する記事

基于响应式的开发模式,我们还可以按照类似的原理,把我们需要修改的数据,都变成响应式;比如,我们可以在 loading 状态下,去修改浏览器的小图标 favicon;和本地存储类似,修改 favicon 时,我们需要找到 head 中有 icon 属性的标签

在下面的代码中,我们把对图标的对应修改的操作封装成了 useFavicon 函数,并且通过 ref 和 watch 的包裹,我们还把小图标变成了响应式数据

import {ref,watch} from 'vue'
export default function useFavicon( newIcon ) {
    const favicon = ref(newIcon)
    const updateIcon = (icon) => {
        document.head
        .querySelectorAll(`link[rel*="icon"]`)
        .forEach(el => el.href = `${icon}`)
    }
watch( favicon,
    (i) => {
        updateIcon(i)
    }
)
    return {favicon,reset}
}

这样在组件中,我们就可以通过响应式的方式去修改和使用小图标,通过对 faivcon.value 的修改就可以随时更换网站小图标;下面的代码,就实现了在点击按钮之后,修改了网页的图标为 geek.png 的操作

<script>
    import useFavicon from &#39;./utils/favicon&#39;
    let {favicon} = useFavicon()
    function loading(){
        favicon.value = &#39;/geek.png&#39;
    }
</script>
<template>
    <button>123</button>
</template>

Vueuse 工具包

我们自己封装的 useStorage,算是把 localStorage 简单地变成了响应式对象,实现数据的更新和localStorage 的同步;同理,我们还可以封装更多的类似 useStorage 函数的其他 use 类型的函数,把实际开发中你用到的任何数据或者浏览器属性,都封装成响应式数据,这样就可以极大地提高我们的开发效率

Vue 社区中其实已经有一个类似的工具集合,也就是 VueUse,它把开发中常见的属性都封装成为响应式函数

VueUse 趁着这一波 Vue 3 的更新,跟上了响应式 API 的潮流;VueUse 的官方的介绍说这是一个 Composition API 的工具集合,适用于 Vue 2.x 或者 Vue 3.x,用起来和 React Hooks 还挺像的

在项目目录下打开命令行里,我们输入如下命令,来进行 VueUse 插件的安装:

npm install @vueuse/core

然后,我们就先来使用一下 VueUse;在下面这段代码中,我们使用 useFullscreen 来返回全屏的状态和切换全屏的函数;这样,我们就不需要考虑浏览器全屏的 API,而是直接使用 VueUse 响应式数据和函数就可以很轻松地在项目中实现全屏功能

<template>
    <h1>click</h1>
</template>
<script>
import { useFullscreen } from &#39;@vueuse/core&#39;
const { isFullscreen, enter, exit, toggle } = useFullscreen()
</script>

useFullscreen 的封装逻辑和 useStorage 类似,都是屏蔽了浏览器的操作,把所有我们需要用到的状态和数据都用响应式的方式统一管理,VueUse 中包含了很多我们常用的工具函数,我们可以把网络状态、异步请求的数据、动画和事件等功能,都看成是响应式的数据去管理

(学习视频分享:web前端开发编程基础视频

以上がVue3 の応答メカニズムの詳細な分析を提供する記事の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。