ref adalah untuk menyelesaikan masalah yang proksi tidak boleh proksi secara langsung nilai asal. Mari kita lihat penggunaan ref:
const name = ref('小黑子')
Bagaimana ref dilaksanakan? Malah, ia adalah untuk "membungkus" nilai asal dengan objek. Mari kita lihat pelaksanaan ref:
function ref(val){ // 使用对象包裹原始值 const wrapper = { value:val } // 利用 reactive 将对象变成响应式数据 return reactive(wrapper) }
ref Pelaksanaannya semudah itu.
ref melakukan dua perkara ini sebagai tindak balas kepada nilai asal:
1 Gunakan objek untuk membungkus nilai asal.
2. Gunakan reaktif untuk menukar objek pakej menjadi data responsif.
Kami menggunakan ref untuk mencipta objek responsif, tetapi bagaimana kita membezakan sama ada objek adalah objek biasa atau objek ref? Jadi isref kami muncul.
Mari kita lihat penggunaannya:
const name = ref('cj') console.log(isRef(name)); // true
Jadi apakah prinsip pelaksanaannya? Pelaksanaan utama masih dalam ref API Mari kita lihat pada kod pelaksanaan khusus:
function ref(val){ const wrapper = { value:val } Object.defineProperty(warpper,'__v_isRef',{ value:true }) return reactive(wrapper) }
Ternyata ia menambahkan atribut yang tidak boleh dikira dan tidak boleh ditulis pada objek pakej di dalam ref, dan nilainya adalah benar. Dengan cara ini kita boleh menyemak atribut untuk menentukan sama ada ia adalah rujukan.
function isRef(val) { return val.__v_isRef ?? false }
Apakah kehilangan tindak balas? Kehilangan tindak balas bermakna data responsif tidak dijawab. Mari lihat kod di bawah:
const obj = reactive({foo:1,bar:2}) const {foo,bar} = obj obj.foo++ // foo不会改变,还是 1
Respons obj di atas telah hilang, jadi pemaparan semula tidak akan dicetuskan. Mengapa ini berlaku? Malah, kerana penggunaan tugasan struktur, pengendali pengembangan juga akan membatalkannya.
const obj = reactive({foo:1,bar:2}) const newObj = {...obj} obj.foo++ // newObj.foo不会改变,还是 1
Ini bersamaan dengan mentakrifkan semula data baharu, yang bukan lagi data respons asal dan secara semula jadi tidak mempunyai keupayaan responsif.
toRef adalah untuk menyelesaikan masalah kehilangan tindak balas. Mari kita lihat pelaksanaannya:
function toRef(obj,key) { const wrapper = { get value() { return obj[key] }, set value(val) { obj[key] = val } } Object.defineProperty(wrapper,'__v_isRef',{ value:true }) return wrapper }
Pass dalam dua parameter, yang pertama ialah data responsif dan yang kedua ialah kunci obj.
Bahagian pertama ialah menyediakan dan mengisytiharkan objek terlebih dahulu menetapkan atribut get value Apabila mengakses nilai toRef, nilai atribut yang sepadan dengan data responsif yang masuk dikembalikan, dan kemudian Set dengan atribut nilai digunakan untuk menetapkan nilai toRef dan mengemas kini nilai atribut yang sepadan dengan data responsif dengan set nilai baharu. Dalam erti kata lain, objek yang dikembalikan oleh toRef masih merupakan data responsif yang digunakan.
Bahagian kedua digunakan untuk menetapkan data yang dikembalikan menjadi data rujukan. Oleh kerana data yang dikembalikan oleh toRef adalah serupa dengan data rujukan, ia secara langsung dianggap sebagai data rujukan demi penyatuan.
Bahagian ketiga ialah mengembalikan objek atribut yang diisytiharkan sepadan dengan data responsif
Dengan cara ini toRef menyelesaikan masalah kehilangan tindak balas.
toRefs adalah untuk menyahbina keseluruhan objek responsif dan menjadikannya responsif. Kod pelaksanaan adalah seperti berikut:
function toRefs() { const ret = {} for (const key in obj) { ret[key] = toRef(obj,key) } return ret }
Gunakan gelung for untuk menukar atribut satu demi satu. Sekarang mari kita lihat penggunaan:
const obj = reactive({foo:1,bar:2}) const {foo,bar} = toRefs(obj) obj.foo++ // foo.value变为2了
Apabila atribut ialah nilai bukan asal, ia masih boleh bertindak balas selepas penyahbinaan
const obj = reactive({foo:{age:18},bar:2}) const {foo,bar} = obj obj.foo.age++ // foo.age变为2了 obj.bar++ // bar没有改变,还是1
reactive 响应数据重新赋值后不再响应,ref 响应数据赋值后依然响应 let obj1 = reactive({foo:1,bar:2}) let obj2 = ref({foo:1,bar:2}) // 假如 obj1 与 obj2 直接展示在页面上 obj1 = {boo:2,far:3} // 页面 obj1 还是 {foo:1,bar:2} obj2.value = {boo:2,far:3} // 页面 obj2 变为 {boo:2,far:3} 了
function ref(val){ const wrapper = { value:val set value(val) { // isObject 这里代表判断是否是非原始值的一个方法 value = isObject(val) === 'Object' ? reactive(val) : val } } Object.defineProperty(warpper,'__v_isRef',{ value:true }) return reactive(wrapper) }
function unref(target) { return new Proxy(target,{ get(target,key,receiver) { const value = Reflect.get(target,key,receiver) return value.__v_isRef ? value.value : value }, set(target,key,newValue,receiver) { const value = target[key] if (value.__v_isRef) { value.value = newValue return true } return Reflect.set(target,key,newValue,receiver) } }) }
{{ name }}
其实原因很简单,在组件 setup 中声明的 ref 响应式数据会传递给 unref 函数进行处理。所以在模板中访问 ref 的值,无需通过 value 属性来访问。
我们使用的 reactive 其实也是有 自动脱 ref 功能的,看一下下方例子:
const count = ref(0) const obj = reactive({conut}) obj.count // 0
我们可以看见 obj.count 是一个 ref 响应式数据。在 count 外层包裹一层对象,再传递给 reactive 后,再访问 obj.count 时就不需要再通过 value 属性访问值了。
也正是因为 reactive 内部也同样实现了自动脱 ref 的能力。
Atas ialah kandungan terperinci vue3 penyelesaian tindak balas nilai asal dan cara menyelesaikan masalah kehilangan tindak balas. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!