ref和reactive的区别
在 Vue 3 中,ref
和 reactive
都是用来创建响应式数据的方法,但它们之间存在一些关键的区别,主要在于它们的用途和工作方式。
ref
ref
是用来创建一个响应式的引用类型。当你使用 ref
创建一个变量时,你会得到一个具有 .value
属性的对象,这个属性实际上指向了响应式的数据。这是 ref
的典型用法:
import { ref } from 'vue';
const myRef = ref(10);
console.log(myRef); // 输出:{ value: 10 }
console.log(myRef.value); // 输出:10
在模板中,你通常需要使用 .value
来访问 ref
的值:
<template>
<div>{{ myRef.value }}</div>
</template>
ref
主要用于以下场景:
- 当你需要在组件的模板中直接绑定一个变量的值。
- 当你需要在计算属性、条件语句或循环中使用一个值。
- 当你想要创建一个单一的响应式值。
reactive
reactive
是用来创建一个完整的响应式对象。与 ref
不同,reactive
直接返回一个普通的 JavaScript 对象,其中的所有属性都是响应式的:
import { reactive } from 'vue';
const state = reactive({ count: 10 });
console.log(state); // 输出:{ count: 10 }
console.log(state.count); // 输出:10
由于 reactive
返回的是普通对象,你不需要 .value
访问器来获取或设置值:
<template>
<div>{{ state.count }}</div>
</template>
reactive
更适合以下场景:
- 当你有一个复杂的数据结构,如对象或数组,需要完全响应式。
- 当你想要避免使用
.value
访问器来简化代码。
总结
ref
适用于单个变量或简单的数据类型,需要.value
访问器来读取或修改值。reactive
适用于复杂的对象结构,不需要额外的访问器,可以直接使用点语法读取或修改属性。
ElementPlus中的slot槽
Element Plus(简称 EP)是 Element UI 的一个全面升级版,专为 Vue 3 设计,提供了丰富的 UI 组件。在 Element Plus 中,`slot`(插槽)是一种非常重要的概念,用于父组件向子组件注入内容。插槽允许你在组件的不同位置放置自定义的内容,这增加了组件的复用性和灵活性。
基本插槽(默认插槽)
基本插槽是最简单的插槽类型,它允许你在组件标签体中放置内容。例如,在使用 `el-button` 组件时,你可以在按钮标签内放置文本:
<template>
<el-button>点击我</el-button>
</template>
这里的 `"点击我"` 就是放置在默认插槽中的内容。
具名插槽
具名插槽允许你指定一个插槽名称,然后在组件模板中使用这个名称来插入内容。这对于组件有多个可以插入内容的位置时非常有用。例如,在 `el-card` 组件中,你可以使用具名插槽来添加标题和内容:
<template>
<el-card>
<template #header>
<div>卡片标题</div>
</template>
<div>卡片内容</div>
</el-card>
</template>
这里的 `#header` 就是一个具名插槽,你可以在 `el-card` 组件中定义这个插槽来展示自定义的头部内容。
作用域插槽
作用域插槽允许父组件访问子组件的数据或方法。这通常通过在插槽中定义一个带有数据的插槽属性来实现。例如,在 `el-table` 中,你可以使用作用域插槽来自定义单元格的内容:
<template>
<el-table :data="tableData">
<template #name="{ row }">
<span>{{ row.name }}</span>
</template>
</el-table>
</template>
<script setup>
import { ref } from 'vue';
const tableData = ref([
{ name: '张三', age: 24 },
{ name: '李四', age: 22 },
]);
</script>
在这个例子中,`#name` 插槽接收一个 `row` 对象,它是当前行的数据。你可以在插槽模板中使用这个对象来展示行数据。
动态插槽
动态插槽允许你使用变量来决定使用哪个插槽。这对于需要动态决定插槽名称的场景很有用。例如:
<template>
<el-card>
<template v-for="slot in ['header', 'footer']" :key="slot" #[slot]="{}">
<div>{{ slot }} 内容</div>
</template>
</el-card>
</template>
这里使用 `v-for` 和 `#[slot]` 语法来动态地渲染 `header` 和 `footer` 插槽。
通过使用插槽,Element Plus 组件可以变得更加灵活和可定制,从而适应不同的UI需求。
对话框、自定义标题、表单、展现控制、新增和修改控制
对话框我们使用的时element-plus中的对话框组件
<div style="padding-left: 50px;">
<el-card style="width: 500px;">
<el-button type="primary" @click = "toadd">新增</el-button>
<el-table :data="tableData" style="width: 100%">
<el-table-column type="selection" property="id" width="55" />
<el-table-column property="name" label="姓名" width="120" />
<el-table-column property="address" label="地址" />
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button type="success" size="small" @click="toupdate(scope.row)">修改</el-button>
<el-button type="danger" size="small" @click="del(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
<el-dialog v-model="dialogFormVisible" width="500">
<template #header>
{{dialogTitle}}商品分类管理
</template>
<el-form :model="form">
<el-form-item label="分类">
<el-input v-model="form.name"></el-input>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogFormVisible = false">取消</el-button>
<el-button type="primary" @click="save">
保存
</el-button>
</div>
</template>
</el-dialog>
自定义标题
<template #header>
{{dialogTitle}}商品分类管理
</template>
通过槽函数进行自定义标题
展现控制:通过控制dialogFormVisible来判断表单是否展示。
新增控制:首先将dialogFormVisible置为true,将隐藏的表单展示出来,接着填写内容,提交新增内容,点击完成时,将dialogFormVisible重新置为false即可。
修改也是类似的控制流程。
雪花算法引起javascript long型精度问题及解决方案
现象:雪花算法生成的ID通常是64位的长整型数字,这在很多编程语言中都可以很好地处理。然而,在JavaScript中,由于其数字类型是基于双精度浮点数(Double-precision 64-bit binary format IEEE 754)实现的,只能保证在-2^53
到2^53-1
(即大约-9,007,199,254,740,991
到9,007,199,254,740,991
)之间的整数精度。这意味着64位雪花算法生成的ID,尤其是那些大于2^53-1
的值,在JavaScript中会丢失精度。
解决方案:
使用[JsonConverter(typeof(LongToStringConverter))]
特性来指示编译器在序列化和反序列化时使用我们的自定义转换器。在序列化过程中,long
类型的值会被转换为字符串,而在反序列化时,字符串会被转换回long
类型。
通过这种方式,可以在.NET
应用程序中有效地处理long
类型在JSON中的字符串表示,确保数据在传输过程中的完整性和兼容性。
internal class LongToStringConverter : JsonConverter<long>
{
public override long Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
// 读取时将字符串转换回long
return long.Parse(reader.GetString());
}
public override void Write(Utf8JsonWriter writer, long value, JsonSerializerOptions options)
{
// 写入时将long转换为字符串
writer.WriteStringValue(value.ToString());
}
}
调用该自定义转换器:
[Table("tb_class")]
public class Classify
{
[JsonConverter(typeof(LongToStringConverter))]
public long? Id { get; set; }
public string? Name { get; set; }
}
什么是RESTful
RESTful(Representational State Transfer 的缩写,表述性状态转移)是一种软件架构风格,主要用于设计网络应用程序的API,特别是Web服务。RESTful API的设计基于HTTP协议,遵循一系列原则和约束条件,以实现简洁、可扩展、易于理解、安全且能够自描述的网络服务。
以下是RESTful API的一些关键特征和原则:
1. **无状态(Stateless)**:
RESTful服务在每个请求之间应该是无状态的,即服务器不会保存任何有关客户端状态的信息。每次请求必须包含所有必要的信息,以便服务器能够理解并处理请求。
2. **客户端-服务器模型(Client-Server Model)**:
RESTful架构将用户界面(客户端)与数据存储(服务器)分离,这使得两者可以独立演化。客户端负责用户界面和用户体验,而服务器负责数据存储和业务逻辑。
3. **缓存(Cacheability)**:
RESTful服务的响应可以被标记为可缓存或不可缓存,这有助于提高性能和减少带宽消耗。
4. **统一的接口(Uniform Interface)**:
RESTful API具有统一的接口,包括:
- **资源定位**:使用URL来唯一标识资源。
- **无状态的HTTP方法**:使用标准的HTTP方法(如GET、POST、PUT、DELETE)来操作资源。
- **状态码**:使用HTTP状态码来表示请求的结果。
- **超媒体作为应用状态引擎(HATEOAS)**:响应中包含链接到其他相关资源的链接,使得客户端能够发现和跟随这些链接,从而进一步操作资源。
5. **分层系统(Layered System)**:
RESTful架构可以构建在分层系统之上,这意味着中间层可以缓存、过滤、授权或重定向请求,而不影响上层或下层的客户端或服务器。
6. **按需代码(Code on Demand)**(可选):
服务器可以扩展客户端的功能,通过在响应中包含代码(如JavaScript、CSS)来执行某些操作,但这不是强制性的。
RESTful API的设计强调了清晰的URL结构和使用标准的HTTP方法来表达资源的操作,使得API易于理解和使用。此外,RESTful API通常返回JSON或XML格式的数据,便于跨语言和跨平台的使用。
对象赋值和Object.Assign的区别
在 Vue 3 中,处理对象赋值时,理解直接赋值和 `Object.assign()` 的区别非常重要,因为这直接影响到数据的响应式行为和性能。
直接赋值
直接赋值通常指的是使用赋值运算符 `=` 来复制一个对象。然而,在 JavaScript 中,对象赋值实际上是浅拷贝,也就是说,你只是在复制对象的引用,而不是对象本身的内容。例如:
const original = { a: 1, b: 2 };
const copy = original;
original.a = 3;
console.log(copy); // 输出:{ a: 3, b: 2 }
在 Vue 中,由于数据的响应式特性,直接赋值一个响应式对象会导致 Vue 无法追踪到对象内部属性的变化,从而可能引发视图更新的问题。这是因为 Vue 通过代理和 getter/setter 来追踪对象属性的读写,直接赋值会绕过这一机制。
Object.assign()
`Object.assign()` 方法用于合并一个或多个源对象到目标对象中。它会浅拷贝源对象的可枚举属性到目标对象上。例如:
const target = {};
const source = { a: 1, b: 2 };
Object.assign(target, source);
console.log(target); // 输出:{ a: 1, b: 2 }
尽管 `Object.assign()` 提供了对象属性的复制,但它仍然只进行浅拷贝,即对于对象的属性,它只会复制引用,不会深入拷贝对象内部的属性。这意味着如果源对象的属性是另一个对象,那么这个属性也会被浅拷贝,即复制引用而不是值。
在 Vue 3 中,使用 `Object.assign()` 来更新响应式对象同样可能导致响应式失效的问题,因为 Vue 无法追踪到新赋值的对象属性。例如,如果你有一个响应式对象,然后使用 `Object.assign()` 更新它,Vue 可能无法察觉到内部属性的变化,除非你使用正确的 Vue API 如 `this.$set` 或 `Vue.set`,或者使用 Vue 3 的 `ref` 和 `reactive` API 来创建响应式数据。
Vue 3 的响应式 API
在 Vue 3 中,推荐使用 Composition API 中的 `reactive` 和 `ref` 来创建和操作响应式数据。对于对象,你可以使用 `reactive`:
import { reactive } from 'vue';
const state = reactive({ a: 1, b: 2 });
state.a = 3; // Vue 能够追踪到这个变化
如果需要深拷贝一个对象并保持响应式,你可以先使用 `JSON.parse(JSON.stringify(obj))` 或者第三方库如 lodash 的 `_.cloneDeep` 方法进行深拷贝,然后再用 `reactive` 包装。
总结来说,直接赋值和 `Object.assign()` 在 Vue 3 中可能不会保持数据的响应式特性,而使用 Vue 的响应式 API (`reactive`, `ref`) 是处理对象赋值和保持响应式行为的最佳实践。
如何实现修改回显
在我们的前端的项目中如果想实现表单的修改功能,思路:首先将要将表单本来的内容填写到新开的表单上,然后进行操作即可
<el-button type="success" size="small" @click="toupdate(scope.row)">修改</el-button>
const toupdate=(row)=>{
dialogFormVisible.value=true
dialogTitle.value = "修改"
Object.assign(form,row)
}
如何实现新增清空数据
在实现新增功能时,因为我们的代码里面使用的一个form所以,在新增界面需要将form的信息清除,这需要进行重新赋空值,注意不能赋null,不允许赋null。
const toadd=()=>{
dialogFormVisible.value=true
dialogTitle.value = "新增"
Object.assign(form,formInit)
}