网站前端开发培训资料,shopee个人开店条件,网上服务,青岛网站建设公司招聘ref()函数
这是一个用来接受一个内部值#xff0c;返回一个响应式的、可更改的 ref 对象#xff0c;此对象只有一个指向其内部值的属性 .value。
作用#xff1a;创建一个响应式变量#xff0c;使得某个变量在发生改变时可以同步发生在页面上。
模板语句中使用这个变量时…ref()函数
这是一个用来接受一个内部值返回一个响应式的、可更改的 ref 对象此对象只有一个指向其内部值的属性 .value。
作用创建一个响应式变量使得某个变量在发生改变时可以同步发生在页面上。
模板语句中使用这个变量时可以直接使用变量名来调用在setup内部调用时则需要在变量明后面加上一个.value获取它的值原因是因为使用ref()返回的是一个RefImpl对象类型。
RefImpl
RefImplRefImpl是用于实现ref的内部类。它用于包装单个基本数据类型值并提供.value属性来访问和更新值。当你使用ref函数创建一个响应式引用时实际上是在内部创建了一个RefImpl实例。
当在控制台上输出一个ref对象时输出的就是refImpl对象。 RefImpl用于包装单个值也可以用来包装一个对象包装一个对象时这个ref.value得到的会是一个响应式proxy代理对象。
reactive()函数 作用创建一个响应式的对象不可重新赋值使用该函数创建的对象也是可以像ref()的一样实现响应式的变化但是不管是模板语句里面还是setup内部都可以像普通的对象一样调用但是使用reactive返回的同样是一个Proxy对象类型的数据。如下所示 ObjectRefImpl
ObjectRefImplObjectRefImpl是用于实现reactive的内部类。它用于包装一个对象并为该对象的每个属性创建响应式代理。当你使用reactive函数创建一个响应式对象时实际上是在内部创建了一个ObjectRefImpl实例。
为什么说reactive创建的对象不可重新赋值
reactive 创建的对象可以重新赋值但不能被重新赋值为一个完全不同的对象。这是因为 reactive 创建的对象是响应式的它会追踪其属性的变化并在属性发生变化时触发视图更新。如果你重新赋值整个对象那么 Vue 将无法继续追踪原始对象的变化因为它不再引用相同的对象。
下面是一个示例说明 reactive 创建的对象可以重新赋值
import { reactive } from vue;const state reactive({name: John,age: 30,
});console.log(state.name); // 输出 John// 可以重新赋值属性值
state.name Alice;console.log(state.name); // 输出 Alice在上述示例中我们可以看到我们成功地重新赋值了 state 对象的 name 属性这是因为我们仅仅修改了属性值而不是整个对象。
然而如果尝试将 state 对象重新赋值为一个全新的对象例如
state reactive({ name: Bob, age: 25 }); // 这是不允许的这将导致一个错误因为这样做相当于放弃了对原始 state 对象的引用Vue 将无法继续追踪原始对象的属性变化。如果需要更改整个对象你应该使用 ref 或 computed 来处理而不是 reactive。
Proxy对象
Proxy 对象是 JavaScript 中的一个内置对象它允许你创建一个代理proxy用于控制对另一个对象的访问和操作。这个代理对象可以拦截和自定义目标对象的各种操作例如属性的读取、写入、删除等从而提供了更高级的元编程能力和数据保护机制。
Proxy 对象的基本语法如下
const proxy new Proxy(target, handler);
- target被代理的目标对象即你想要拦截操作的对象。 - handler一个包含各种拦截操作的处理器对象它定义了代理对象的行为。例如你可以使用 Proxy 来创建一个简单的日志记录器以监视目标对象的属性访问和修改
const target {name: John,age: 30,
};const handler {get(target, key) {console.log(Getting ${key});return target[key];},set(target, key, value) {console.log(Setting ${key} to ${value});target[key] value;},
};const proxy new Proxy(target, handler);console.log(proxy.name); // 会触发代理的get拦截打印 Getting name然后返回 John
proxy.age 31; // 会触发代理的set拦截打印 Setting age to 31
Proxy 的强大之处在于你可以定义自定义行为来拦截目标对象上的各种操作。这使得它在元编程、数据验证、数据保护和许多其他场景中非常有用。
需要注意的是Proxy 是 ECMAScript 6 的一部分因此在一些老版本的浏览器中可能不受支持。但现代浏览器和 Node.js 环境中通常都支持 Proxy。
toRefs方法
toRefs是Vue 3中一个有用的辅助函数用于将响应式对象的属性转换为普通的响应式引用ref。这对于在模板中访问响应式对象的属性以及将它们传递给子组件时非常有用。
下面是toRefs的使用示例
假设你有一个响应式对象(reactive)
import { reactive, toRefs } from vue;const state reactive({name: John,age: 30,
});使用toRefs将这个响应式对象的属性转换为响应式引用
const stateRefs toRefs(state);现在stateRefs是一个包含了name和age属性的对象但这些属性已经被转换为响应式引用。你可以像访问普通的引用一样访问它们的值
console.log(stateRefs.name.value); // John
console.log(stateRefs.age.value); // 30在模板中使用时你可以直接使用stateRefs.name和stateRefs.ageVue会自动解开引用并进行响应式追踪。
使用toRefs的主要优点是在将响应式对象的属性传递给子组件时子组件可以直接使用属性的引用而不需要手动解包。这可以避免一些潜在的问题例如丢失响应性。
ref和reactive得到的不同响应式对象
ref
ref 用于创建响应式引用它返回一个包装对象这个包装对象具有一个名为 .value 的属性该属性用于读取和写入值。内部实现上ref 创建了一个名为 RefImpl 的对象它是 Vue 3 内部的私有类用于包装值并添加响应性。你可以通过 ref 创建基本数据类型的响应式数据例如数字、字符串等。
import { ref } from vue;const count ref(0); // 返回一个 RefImpl 对象
console.log(count.value); // 0
count.value 1; // 更新值reactive
reactive 用于创建一个响应式代理对象它会追踪对象内部属性的变化。内部实现上reactive 使用了 JavaScript 的 Proxy 对象将目标对象包装在代理之下从而实现响应性。你可以通过 reactive 创建包含多个属性的响应式对象通常用于复杂的数据结构。
import { reactive } from vue;const state reactive({name: John,age: 30,
}); // 返回一个 Proxy 对象
console.log(state.name); // John
state.age 31; // 视图会自动更新reactive对象使用toRefs时发生了什么
使用 toRefs 将一个 reactive 对象的属性转换为响应式引用ref时会将原始对象的每个属性都包装成独立的 ref从而使这些属性可以在模板中正常工作并保持响应性。但是这些属性会变成ObjectRefImpl类型。
以下是使用 toRefs 的示例
import { reactive, toRefs } from vue;const state reactive({name: John,age: 30,
});const stateRefs toRefs(state);console.log(stateRefs.name.value); // 输出 John
console.log(stateRefs.age.value); // 输出 30在上面的示例中toRefs 函数将 state 对象的每个属性都包装为 ref并将这些 ref 存储在 stateRefs 对象中。现在你可以像访问普通的 ref 一样访问这些属性而不需要 .value。
toRefs 的主要作用是确保 reactive 对象的属性在模板中可以正确追踪和更新因为模板编译器可以正确处理 ref而 ref 具有 .value 属性使得属性的访问和修改都能够正常工作。这对于将属性传递给子组件或在模板中使用响应式数据非常有用因为它确保了属性的正确响应性行为。
需要注意的是toRefs 创建的 ref 仍然是响应式的但是它们只包装了原始属性的值而不是整个对象。这意味着你只能访问和修改属性的值而不能修改整个对象或添加新的属性。如果需要修改整个对象你应该使用 reactive 创建一个新的代理对象。
为什么reactive不能用.value访问
reactive 创建的对象不能直接使用 .value 来访问属性的值因为 reactive 返回的对象是一个代理对象Proxy不同于使用 ref 创建的包装对象。
使用 reactive 创建的对象是一个代理它会在访问和修改属性时自动进行响应式追踪而不需要额外的 .value 属性。因此你可以像访问普通 JavaScript 对象一样访问 reactive 对象的属性而不需要额外的 .value。这正是 Vue 3 中的响应式系统的设计理念之一使代码更加简洁和自然。
例子
Vue——vue3element plus实现多选表格使用ajax发送id数组_北岭山脚鼠鼠的博客-CSDN博客
继上次之后再次实现了一个弹出式的编辑框,然后要将某一行tableItem数据传送给子组件进行展示.
然后这里就要用到props。
效果如下 控制台输出了一些数据
这是父组件里面的输出。
除了传进来的表格的行数据以外又准备了一个reactive包装的对象rea和一个ref包装的对象a和一个ref类型的tableitem接收表格的行数据。一共三个。
const tableItem ref()let rea reactive({ name: yhy, age: 23 })const a ref({ name: John, age: 30 });var onEdit (data) {tableItem.value data //发送当前行数据给组件console.log(data) //输出了一个Proxy数据console.log(tableItem部分———————Ref————————————————————————)console.log(tableItem) //输出了一个RefImpl数据console.log(tableItem.value)console.log(tableItem.value.shopname) //console.log(rea部分——————Reactive—————————————————————————)console.log(rea)console.log(rea.name)console.log(toRefs(rea))console.log(toRefs(rea).name)console.log(a部分———————Ref————————————————————————)console.log(a);console.log(a.value);console.log(a.value.name);//console.log(tableItem.value.get(name)) //会提示不是一个对象//console.log(tableItem.get(name)) //会提示console.log(tableItem.value.get(name))showDialog.value true //显示表单dialogFormVisible.value true //显示弹窗}
输出如下 103行是得到的表格数据可以看见是Proxy类型的对象说明和reactive创建的一样的都是响应式的对象。
tableItem
106得到的是RefImpl数据这个正是ref返回得到
107得到的是将表格数据(proxy或者说reactive)赋给ref.value之后得到的虽说ref一般都是用来封装数值但是像这样封装对象也是可以的。
108就是ref.value.shopname得到的因为ref.value是reactive类型的对象所以可以直接用.属性名的方式得到。
rea
110和111一个是reactive的直接输出一个是其属性的输出。
112是使用了toRefs将一个响应式对象(proxy)变成了普通对象将其属性变成了ObjectRefImpl类似ref那样。
113是输出了这个转换后的普通对象的属性可以看见是ObjectRefImpl类型这时可以使用value访问它的值。
a部分
和tableItem差不多都是封装了一个对象进了value,但是这里那个对象使用了Proxy代理对象。
子组件里面的输出 props: {tableItem: {},},setup(props) {const tableItem2 ref();const temp ref();tableItem2.value toRefs(props).tableItem.valueconsole.log(1--------)console.log(props); //props是一个proxy代理对象console.log(2--------)console.log(props.tableItem) //里面包着的tableItem也是一个代理对象console.log(3--------)//console.log(props.tableItem.value) console.log(props.tableItem.shopname) //Proxy代理对象不需要用value可以直接访问console.log(4--------)temp.value toRefs(props.tableItem) //使用一个ref接受tableItem这个reactive创建的proxy对象然后将里面的属性全部变成了拥有ObjectRefImpl类型console.log(temp)console.log(temp.value.shopname) //为什么这里ObjectRefImpl不需要用valueconsole.log(temp.value.shopname.value) //shopname是ObjectRefImpl类型但是.value输出undefinedconsole.log(5--------)console.log(toRefs(props).tableItem) //tableItem变成了ObjectRefImpl类型但是value还是proxy类型console.log(6--------)console.log(toRefs(props).tableItem.value) //这里tableItem是ObjectRefImpl类型用.value输出了proxy类型console.log(toRefs(props).tableItem.value.shopname) //
} 1下可以看见传进来的props也是一个proxy代理对象要用到的数据在里面也是一个对象的形式
2里输出了传来的tableItem(reactive) 3里直接输出了里面的属性
4里先是用toRefs将reactive对象变成普通对象(属性变成了ObjectRefImpl)封装进一个ref对象temp.value里面然后又成了proxy代理对象但里面的6个属性还是ObjectRefImpl类型的 然后之前说过这里ObjectRefImpl和ref一样需要用value访问数据,这里却不用并且用了也访问不到......... 5里面使用toRefs将props变成了普通对象并将其下的tableItem变成了ObjectRefImpl类型但是tableItem.value是proxy代理对象其下的6个属性类型没变。
所以6里面可以用.value输出一个proxy类型用.value.shopname输出一个沙县小吃。
特例
那么toRefs 修改后的数据的属性变成了ObjectRefImpl类型了但是如果属性是一个对象时并且这个对象里面里面还包含了多个属性时要怎么访问这个对象里面的多个属性?
当使用 toRefs 修改后的数据的属性是一个对象并且这个对象里面包含了多个属性时你可以直接使用 .value 访问该属性然后再使用点符号或中括号符号来访问该对象内部的多个属性。
下面是一个示例说明如何访问 toRefs 修改后的数据对象内部的多个属性
import { reactive, toRefs } from vue;const state reactive({person: {name: John,age: 30,},city: New York,
});const stateRefs toRefs(state);// 访问对象属性
console.log(stateRefs.person.value.name); // 输出 John
console.log(stateRefs.person.value.age); // 输出 30console.log(stateRefs.city.value); // 输出 New York在上述示例中我们首先使用 .value 访问 person 和 city 这两个属性然后再使用点符号或中括号符号访问这些属性内部的属性。这样可以访问 person 对象内的 name 和 age 属性以及 city 属性。
总之使用 toRefs 修改后的数据对象的属性仍然需要使用 .value 来访问然后再使用标准的属性访问语法来访问对象内部的多个属性。这样可以访问和操作对象内部的数据。 父组件代码
template div idshoplistel-table refmultipleTableRef :datadata.arr stylewidth: 100% height90% stripeselection-changehandleSelectionChangetemplate #defaultel-table-column typeselection width40 /el-table-column propertyshopname label店名 width120 show-overflow-tooltip /el-table-column propertyscore label评分 sortable width80 /el-table-column propertysales label销量 sortable width80 /el-table-column propertytype label类型 width70 /el-table-column propertyoperations label操作 width70template #defaultscope el-button link typeprimary clickonEdit(scope.row)sizesmallEdit/el-button/template/el-table-column/template/el-tablediv stylemargin-top: 20px; margin-left:20pxel-button clicktoggleSelection(data.arr)全选/el-buttonel-button clicktoggleSelection()清除/el-buttonel-button clickdelete_post批量删除/el-button/div/divel-dialog v-modeldialogFormVisible titleShipping addressdialog-component v-ifshowDialog :showDialogshowDialog :tableItemtableItem/dialog-component/el-dialog
/templatescript
import { onMounted, ref } from vue;
import { getCurrentInstance } from vue
import { reactive, toRefs } from vue/reactivity;
import $ from jquery
import DialogComponent from ../components/DialogComponent.vue;
export default {name: ElementView,components: {DialogComponent},setup() {const instance getCurrentInstance(); //这个玩意不能用在生产环境好像const multipleTableRef ref(null);const multipleSelection ref([])const data2 ref([])const list reactive([])const tableItem ref({ name: yhy })const dialogFormVisible ref(false)const showDialog ref()let rea reactive({ name: yhy, age: 23 })const a ref({ name: John, age: 30 });var toggleSelection (rows) {console.log(instance) //输出了这个vue组件的实例对象console.log(instance.refs.multipleTableRef) //输出了一个代理对象var ultipleTabInstance toRefs(instance.refs.multipleTableRef)//将代理对象转换为了普通对象不转会报错console.log(ultipleTabInstance); //输出了一个普通对象if (rows) {rows.forEach(row {ultipleTabInstance.toggleRowSelection.value(row, undefined)console.log(row)});} else {ultipleTabInstance.clearSelection.value()}}//备用方案onMounted(() {// console.log(multipleTableRef);})//该方法用于将表格数据赋给ref变量var handleSelectionChange (val) {console.log(val)multipleSelection.value val;}//此处是实现删除逻辑的方法var delete_post () {data2.value multipleSelection.valueconsole.log(data2.value)data2.value.forEach(a {console.log(a.id)list.unshift(a.id)})console.log(list)//将该id数组传到后端进行批量删除$.ajax({url: http://127.0.0.1:4000/posts/add2,type: POST,headers: {Content-Type: application/json;charsetutf-8,},data: JSON.stringify({ content: list }), success(resp) {if (resp success) {console.log(caa)list.value null}}});}var onEdit (data) {tableItem.value data //发送当前行数据给组件console.log(data) //输出了一个Proxy数据console.log(tableItem部分———————Ref————————————————————————)console.log(tableItem) //输出了一个RefImpl数据console.log(tableItem.value)console.log(tableItem.value.shopname) //console.log(rea部分——————Reactive—————————————————————————)console.log(rea)console.log(rea.name)console.log(toRefs(rea))console.log(toRefs(rea).name)console.log(a部分———————Ref————————————————————————)console.log(a);console.log(a.value);console.log(a.value.name);//console.log(tableItem.value.get(name)) //会提示不是一个对象//console.log(tableItem.get(name)) //会提示console.log(tableItem.value.get(name))showDialog.value true //显示表单dialogFormVisible.value true //显示弹窗}//到这里为止都是加上的var data reactive({arr: [{id: 1,shopname: 沙县小吃,score: 5.5,sales: 1200,hh: 12,type: 快餐},{id: 2,shopname: 法式牛排餐厅,score: 7.5,sales: 2400,hh: 12,type: 西餐},{id: 3,shopname: 沙县大吃,score: 6.5,sales: 200,hh: 12,type: 快餐},{id: 4,shopname: 南昌瓦罐汤,score: 6.9,sales: 2400,hh: 12,type: 快餐},]})return {data,multipleTableRef,toggleSelection,handleSelectionChange,delete_post,data2,onEdit,showDialog,tableItem,dialogFormVisible,close,rea, a}}
}
/scriptstyle/style
子组件代码
templateel-form label-width120pxel-form-item labelActivity nameel-input v-modeltableItem2.shopname :valuetableItem2.shopname //el-form-itemel-form-item labelActivity nameel-input v-modeltableItem2.score :valuetableItem2.score //el-form-itemel-form-item labelActivity nameel-input v-modeltableItem2.sales :valuetableItem2.sales //el-form-itemel-form-item labelActivity nameel-input v-modeltableItem2.type :valuetableItem2.type //el-form-itemel-form-itemel-button typeprimary clickonSubmitCreate/el-buttonel-buttonCancel/el-button/el-form-item/el-form
/template
script
import { toRefs } from vue/reactivity;
import { ref } from vue;export default ({name: DialogComponent,props: {tableItem: {},},setup(props) {const tableItem2 ref();const temp ref();tableItem2.value toRefs(props).tableItem.valueconsole.log(1--------)console.log(props); //props是一个proxy代理对象console.log(2--------)console.log(props.tableItem) //里面包着的tableItem也是一个代理对象console.log(3--------)//console.log(props.tableItem.value) console.log(props.tableItem.shopname) //Proxy代理对象不需要用value可以直接访问console.log(4--------)temp.value toRefs(props.tableItem) //使用一个ref接受tableItem这个reactive创建的proxy对象然后将里面的属性全部变成了拥有ObjectRefImpl类型console.log(temp)console.log(temp.value.shopname) //为什么这里ObjectRefImpl不需要用valueconsole.log(temp.value.shopname.value) //shopname是ObjectRefImpl类型但是.value输出undefinedconsole.log(5--------)console.log(toRefs(props).tableItem) //tableItem变成了ObjectRefImpl类型但是value还是proxy类型console.log(6--------)console.log(toRefs(props).tableItem.value) //这里tableItem是ObjectRefImpl类型用.value输出了proxy类型console.log(toRefs(props).tableItem.value.shopname) //const onSubmit () {console.log(tableItem2.value)}return {onSubmit,tableItem2,}},
})/scriptstyle scoped/style