Responsif sentiasa menjadi salah satu ciri khas Vue sebaliknya, pembolehubah dalam JavaScript tidak mempunyai konsep responsif anda Konsep pertama yang diterapkan apabila pembelajaran JavaScript ialah kod dilaksanakan dari atas ke bawah
Mari lihat kod berikut Selepas kod dilaksanakan, dua hasil berganda yang dicetak juga adalah 2 ;Walaupun kita mengubahsuai nilai kiraan. dalam kod tersebut, nilai double tidak akan berubah sama sekali
let count = 1 let double = count * 2 count = 2
Nilai double dikira berdasarkan nilai kiraan didarab dengan dua Jika sekarang kita mahu double boleh berubah dengan perubahan kiraan, maka kita perlu mengira semula dua kali
setiap kali nilai kiraan diubah suai Sebagai contoh, dalam kod berikut, kita mula-mula merangkum logik pengiraan dua kali ke dalam fungsi, dan kemudian Selepas mengubah suai kiraan, laksanakan semula dan. anda akan mendapat nilai berganda terkini
let count = 1 // 计算过程封装成函数 let getDouble = n=>n*2 //箭头函数 let double = getDouble(count) count = 2 // 重新计算double ,这里我们不能自动执行对double的计算 double = getDouble(count)
Logik pengiraan dalam pembangunan sebenar akan menjadi lebih rumit daripada mengira dua kali ganda, tetapi ia boleh dirangkumkan ke dalam fungsi untuk pelaksanaan langkah seterusnya , apa yang perlu kita pertimbangkan ialah bagaimana untuk membuat nilai dua kali secara automatik dikira
Jika kita boleh membuat fungsi getDouble dilaksanakan secara automatik, iaitu, seperti yang ditunjukkan dalam rajah di bawah, kita menggunakan beberapa mekanisme JavaScript untuk membalut kiraan dalam lapisan , apabila mengira diubah suai, nilai double dikemas kini secara serentak, kemudian ada perasaan bahawa double secara automatik berubah dengan perubahan kiraan Ini adalah prototaip responsif
Apakah prinsip responsif? Tiga penyelesaian responsif telah digunakan dalam Vue, iaitu defineProperty, Proxy dan value setter Mari kita lihat dulu pada Vue 2's defineProperty API
Di sini saya akan menggambarkannya dengan contoh menggunakan defineProperty untuk memproksi atribut count dengan cara ini, kami memintas atribut nilai objek obj Apabila membaca atribut count, laksanakan fungsi get, apabila mengubah suai atribut count, laksanakan fungsi set, dan set semula di dalam set. fungsi. Dikira dua kali
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 有种自动变化的感觉
supaya kita boleh mencapai fungsi responsif yang mudah Dalam bahagian keempat kursus, saya juga akan membawa anda untuk menulis sistem responsif yang lebih lengkap
tetapi tentukanProperty As. prinsip pelaksanaan responsif dalam Vue 2, API juga mempunyai beberapa kelemahan dalam sintaksnya sebagai contoh, dalam kod berikut, jika kita memadamkan atribut obj.count, fungsi yang ditetapkan tidak akan dilaksanakan, dan double akan tetap; nilai sebelumnya; inilah sebabnya dalam Vue 2 , kita memerlukan $delete
fungsi khas untuk memadam data
delete obj.count console.log(double) // doube还是4
Mekanisme responsif Vue 3 dilaksanakan berdasarkan Proksi setakat nama Proksi, anda juga boleh melihat bahawa ini bermakna proksi , kepentingan penting Proksi ialah ia menyelesaikan kelemahan responsif Vue 2
Mari lihat kod berikut, di mana kita proksi objek obj melalui Proksi baharu, dan kemudian proksi objek melalui fungsi get, set dan deleteProperty Baca, ubah suai dan padam operasi, dengan itu merealisasikan fungsi responsif
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)
Dari sini kita dapat melihat bahawa fungsi yang dilaksanakan oleh Proxy adalah serupa dengan definePropery Vue 2, kedua-duanya boleh dicetuskan apabila pengguna mengubah suai fungsi set data untuk merealisasikan fungsi mengemas kini dua kali secara automatik. Selain itu, Proksi juga telah menambah baik beberapa kekurangan definePropery Contohnya, ia boleh memantau pemadaman sifat
Proksi memantau objek, bukan sifat tertentu, jadi ia bukan sahaja boleh memproksi yang tidak wujud apabila Hartanah ditakrifkan boleh. juga proksi untuk struktur data yang lebih kaya, seperti Map, Set, dsb., dan kami juga boleh melaksanakan proksi untuk operasi pemadaman melalui deleteProperty
Sudah tentu, untuk membantu anda memahami Proksi, kami juga boleh menggunakan double -berkaitan Kod ditulis dalam set dan fungsi deleteProperty untuk pelaksanaan Pada separuh kedua kursus, saya akan membawa anda untuk membuat enkapsulasi yang lebih lengkap sebagai contoh, dalam kod berikut, fungsi reaktif Vue 3 boleh mengubah objek menjadi data responsif, dan Reaktif dilaksanakan berdasarkan Proksi; kami juga boleh menggunakan watchEffect untuk mencetak data selepas mengubah suai obj.count
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) })
Dengan Proksi, mekanisme reaktif lebih lengkap tetapi dalam Vue 3, masih ada Terdapat satu lagi logik pelaksanaan responsif, iaitu menggunakan fungsi get dan set objek untuk memantau Pelaksanaan responsif ini hanya boleh memintas pengubahsuaian atribut tertentu Ini juga merupakan pelaksanaan ref API dalam Vue 3
Dalam kod berikut, kami memintas atribut nilai kiraan dan memintas operasi yang ditetapkan, yang juga boleh mencapai fungsi yang serupa
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)
Jadual perbandingan tiga prinsip pelaksanaan adalah seperti berikut untuk membantu anda memahami tiga Perbezaan antara responsif
实现原理 | defineProperty | Proxy | value setter |
---|---|---|---|
实际场景 | Vue 2 响应式 | Vue 3 reactive | Vue 3 ref |
优势 | 兼容性 | 基于proxy实现真正的拦截 | 实现简单 |
劣势 | 数组和属性删除等拦截不了 | 兼容不了 IE11 | 只拦截了 value 属性 |
实际应用 | Vue 2 | Vue 3 复杂数据结构 | Vue 3 简单数据结构 |
简单入门响应式的原理后,接下来我们学习一下响应式数据在使用的时候的进阶方式;我们看下使用 <script setup>
重构之后的 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 内部进阶地使用响应式机制,去封装独立的函数;在后续的实战应用中,我们也会经常对通用功能进行封装;如下图所示,我们可以把日常开发中用到的数据,无论是浏览器的本地存储,还是网络数据,都封装成响应式数据,统一使用响应式数据开发的模式;这样,我们开发项目的时候,只需要修改对应的数据就可以了
基于响应式的开发模式,我们还可以按照类似的原理,把我们需要修改的数据,都变成响应式;比如,我们可以在 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 setup> import useFavicon from './utils/favicon' let {favicon} = useFavicon() function loading(){ favicon.value = '/geek.png' } </script> <template> <button @click="loading">123</button> </template>
我们自己封装的 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> <h2 @click="toggle">click</h2> </template> <script setup> import { useFullscreen } from '@vueuse/core' const { isFullscreen, enter, exit, toggle } = useFullscreen() </script>
useFullscreen 的封装逻辑和 useStorage 类似,都是屏蔽了浏览器的操作,把所有我们需要用到的状态和数据都用响应式的方式统一管理,VueUse 中包含了很多我们常用的工具函数,我们可以把网络状态、异步请求的数据、动画和事件等功能,都看成是响应式的数据去管理。
Atas ialah kandungan terperinci Apakah mekanisme reaktif dalam Vue3. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!