1、ref和reactive的区别
ref:
1. 用途:
ref 主要用于包裹基本类型值(如 Number、String、Boolean)或者用来创建一个可被 Vue 追踪的引用对象。当需要对某个基本类型值进行响应式处理时,`ref` 是非常有用的。它返回一个对象,其 .value 属性持有实际的值
2. 响应式:
当修改 .value 时,Vue 会注意到这个变化并触发相应的视图更新。这对于表单输入绑定或者简单的数据响应式处理非常适用
3. 使用场景:
适合于简单数据属性的响应式处理,或者是你需要直接操作DOM元素时
reactive:
1.用途:
reactive`则用于使一个对象的所有属性变为响应式的。当有一个包含多个属性的对象,并且希望这些属性都能自动追踪变化时,就应当使用 reactive。它返回一个新的代理对象,可以直接通过这个代理对象修改其属性,而所有变动都会被Vue自动追踪
2. 响应式:
修改代理对象的任何属性都会触发Vue的响应式系统,进而更新依赖于这些属性的视图
3. 使用场景:
更适用于复杂的、包含多个层级的数据结构。如果有一个包含多个嵌套对象的状态对象,使用 reactive`可以让你轻松地保持整个状态树的响应式
总结:
基本类型 vs 对象:
如果要使基本类型数据响应式,使用 ref;如果要使一个对象或对象的属性响应式,使用 reactive
访问方式:ref`通过 .value`访问实际数据,而 reactive 直接通过属性访问
适用场景:简单数据用 ref,复杂数据结构或对象用 reactive
2、ElementPlus中什么是slot槽
slot
是一种在Vue组件内部预留的占位区域,允许你在使用组件时插入自定义内容。这种机制让组件变得更加灵活和可重用,它允许外部使用者决定在组件内部的特定位置显示什么内容2.1 插槽的分类
默认插槽:没有指定name属性的插槽,即为默认插槽。父组件在插入内容时,如果没有指定插槽名称,则会插入到默认插槽中。
具名插槽:通过指定name属性来定义的插槽。父组件在插入内容时,需要使用v-slot指令(或简写为#)加上插槽名称来指定内容应该插入到哪个具名插槽中。
作用域插槽:一种特殊的插槽,它允许子组件将其内部的数据“暴露”给父组件,父组件可以根据这些数据来定制插槽的内容。作用域插槽通过v-slot来接收子组件传递的数据。
2.2 插槽的使用
表头插槽(header slot):用于自定义表格的表头内容。在ElementPlus中,表头插槽的名称可能以
header-
开头,并可以附加column-key
属性来指定该插槽对应的列。列插槽(default slot):用于自定义表格的列内容。在ElementPlus中,列插槽的名称为
default
,并可以在插槽中使用row
和column
参数来获取当前行和列的数据。底部插槽(footer slot):用于自定义表格的底部内容。在ElementPlus中,底部插槽的名称可能以
footer-
开头,并可以附加column-key
属性来指定该插槽对应的列。3.2 示例
基本使用:
<el-button>点击我</el-button>
具名slot:
<el-dialog> <template #title> 自定义对话框标题 </template> 对话框内容 <template #footer> 自定义对话框底部操作按钮 </template> </el-dialog>
作用域slot:
<el-table :data="tableData"> <el-table-column prop="name" label="姓名"> <template #default="scope"> {{scope.row.name} </template> </el-table-column> </el-table>
3、对话框、自定义标题、表单、展现控制、新增和修改控制
<template> <div style="padding-left: 50px;"> <el-card style="width: 500px;"> <!-- 新增按钮: 点击后显示模态对话框,用于输入新的商品分类信息 --> <el-button type="primary" size="small" @click="toadd">新增</el-button> <!-- 列出了编号、商品分类,每行有选择框、分类名称和操作列(修改/删除按钮) --> <el-table :data="state.tableData"> <el-table-column type="selection" width="55" /> <el-table-column property="id" label="编号" /> <el-table-column property="name" label="商品分类" /> <!-- 操作列: --> <!-- 修改: 点击后填充表单并打开模态框供用户编辑分类信息。 --> <!-- 删除: 根据当前行的ID调用删除功能。 --> <el-table-column align="center" label="操作"> <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-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> <script setup> import {ref,reactive,onMounted} from 'vue' import {ClassifyList,ClassifySave,ClassifyDelete} from '../api/classify.js' // dialogFormVisible: 控制模态对话框的显示隐藏 const dialogFormVisible = ref(false) // dialogTitle: 显示对话框标题,区分新增和修改 const dialogTitle = ref("新增") // form: 用于双向绑定表单输入的反应式对象,包含分类ID和名称 const form = reactive({ id: null, name:null, }) // formInit: 用于保存表单的初始状态,便于重置表单 var formInit = reactive({}) //封装一个加载方法,加载页面 // refresh: 调用ClassifyList API获取分类列表数据,并更新到state.tableData const refresh = ()=>{ ClassifyList() .then(res =>{ // state.tableData: 存储表格数据的反应式数组 state.tableData = res.data }) .catch(err =>{ console.log(err) }) } onMounted(()=>{ refresh() Object.assign(formInit, form) }) // var tableData = ref([]) const state = reactive({ tableData:[] }) // toadd: 显示新增分类的模态框,重置表单 const toadd = ()=>{ dialogFormVisible.value = true dialogTitle.value = "新增" Object.assign(form, formInit) } // toupdate: 显示修改分类的模态框,并将当前行数据填充到表单 const toupdate = (row)=>{ dialogFormVisible.value = true dialogTitle.value = "修改" Object.assign(form, row) } // save: 调用ClassifySave API保存表单中的分类信息,关闭模态框并刷新列表 const save = ()=>{ ClassifySave(form) .then(()=>{ dialogFormVisible.value = false refresh() }) } // del: 调用ClassifyDelete API删除指定ID的分类,完成后刷新列表 const del = (id)=>{ ClassifyDelete(id) .then(()=>{ refresh() }) } </script> <style> .container { display: flex; align-items: center; /* 垂直居中对齐 */ } .container img{ widows: 50px; height: 50px; margin-right: 15px; } </style>
新增结果:
修改结果:
删除结果:
4、雪花算法引起javascript long型精度问题及解决方案
雪花算法(Snowflake Algorithm)是由Twitter开源的一种分布式ID生成算法,它可以生成全局唯一、趋势递增的ID。这个算法生成的ID是一个64位的整数,由时间戳、数据中心ID、机器ID和序列号组成。然而,在JavaScript中处理这种长整型数字时,可能会遇到精度问题,因为JavaScript中的Number类型虽然能表示很大范围的数值,但它遵循IEEE 754浮点数标准,对于超过53位的整数无法精确表示。
解决方案:
在自己的模型类中加上:
//负责定义如何将 long 类型转换为字符串以及如何将字符串转换回 long 类型 [JsonConverter(typeof(LongToStringConverter))]
然后在模型类中新建一个LongToStringConverter类,用于处理精度的问题
using System.Text.Json; using System.Text.Json.Serialization; namespace KFC527.Models { 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()); } } }
5、什么是RESTful
5.1 定义
RESTful是一种软件架构风格,它遵循REST(Representational State Transfer)原则,使用HTTP协议传输数据,并通过URL来定位和操作资源
5.2 特点
无状态协议:RESTful使用无状态协议,即服务器不维护与客户端的连接状态,每个请求都是独立的。这种无状态协议使得RESTful更加灵活和可扩展,可以轻松地支持并发请求和负载均衡。
基于HTTP协议:RESTful使用HTTP协议来传输数据,HTTP协议是一种通用的协议,可以轻松地与其他系统进行集成。
资源唯一标识:在RESTful中,每个资源都有一个唯一的URL,可以通过HTTP请求来获取或修改该资源的状态。
标准化:RESTful采用了一些标准化的概念和规则,如HTTP协议、URL、JSON等,使得开发人员可以更加轻松地设计和实现系统。
5.3 RESTful的核心规范与约束
统一接口:RESTful架构的核心规范是统一接口,它包含四个子约束:
资源标识:每个资源都拥有一个资源标识,可以用来唯一地标明该资源。
通过标准的动词对资源进行操作:客户端使用GET、POST、PUT、DELETE四个表示操作方式的动词对服务端资源进行操作。其中,GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。
自描述性消息:资源的自描述性,即资源的表现形式(如XML或JSON)能够自我描述其结构和内容。
HATEOAS(超媒体作为应用状态引擎):客户端可以通过服务端返回的响应来获取下一步操作所需要的信息,如操作的URL等,从而无需额外的文档即可调用到所有的服务器资源。
5.4 RESTful的应用场景
RESTful适用于许多不同的应用场景,包括:
Web 应用程序:如社交媒体网站、博客、在线商店等。
移动应用程序:如手机应用程序、平板电脑应用程序等。
后端应用程序:如数据库服务器、消息队列服务器等。
物联网设备:如智能家居设备、智能城市设备等。
5.5 RESTful的优势
可扩展性:由于RESTful使用无状态协议,可以轻松地支持并发请求和负载均衡,从而提高系统的可扩展性。
可靠性:RESTful使用HTTP协议来传输数据,HTTP协议是一种通用的协议,可以保证数据的可靠性和安全性。
易于使用和管理:RESTful使用标准化的概念和规则,如HTTP协议、URL、JSON等,使得开发人员可以更加轻松地设计和实现系统。
跨平台支持:RESTful可以用于构建跨平台的应用程序,如Web应用程序、移动应用程序、后端应用程序等。
6、对象赋值和Object.Assign的区别
6.1 对象赋值
对象赋值在JavaScript中是通过等号(
=
)将一个对象的引用赋给另一个变量。这意味着两个变量都指向堆内存中的同一个对象实例。因此,修改其中一个变量所引用的对象的属性,也会影响到另一个变量所引用的对象。6.1.1 特点
两个变量共享同一个对象实例
修改一个变量的属性会反映到另一个变量上
不涉及对象的复制,只是引用传递
6.1.2 实例
let obj1 = { name: 'Alice', age: 30 }; let obj2 = obj1; // obj2 指向 obj1 所引用的对象 obj2.name = 'Bob'; // 修改 obj2 的 name 属性 console.log(obj1.name); // 输出 'Bob',因为 obj1 和 obj2 指向同一个对象
6.2 Object.assign()
Object.assign()
是JavaScript的一个静态方法,用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象6.2.1 特点
浅拷贝:只复制对象自身的可枚举属性到目标对象,不会复制继承属性或不可枚举属性
如果源对象的属性值是一个对象的引用,则只复制引用,而不是对象本身
如果目标对象和源对象有同名属性,则源对象的属性值会覆盖目标对象的属性值
第一个参数是目标对象,后面的参数都是源对象
6.2.2 实例
let target = { name: 'Alice', age: 30 }; let source1 = { age: 25 }; let source2 = { job: 'Engineer' }; Object.assign(target, source1, source2); Object.assign(目标对象, 源对象, 源对象); console.log(target); // 输出 { name: 'Alice', age: 25, job: 'Engineer' }
6.3 区别
对象赋值 Object.assign() 本质 引用传递,两个变量指向同一个对象 浅拷贝,复制可枚举属性到新对象 影响 修改一个变量的属性会影响另一个变量 修改源对象属性不会影响目标对象(除非引用类型) 用途 简单地让两个变量共享同一个对象 合并对象属性,创建新对象 深拷贝 不涉及深拷贝 不支持深拷贝,只复制引用类型属性的引用
7、如果实现修改回显
7.1
form
的初始化与更新// form: 用于双向绑定表单输入的反应式对象,包含分类ID和名称 const form = reactive({ id: null, name:null, })
和
// toupdate: 显示修改分类的模态框,并将当前行数据填充到表单 const toupdate = (row)=>{ dialogFormVisible.value = true dialogTitle.value = "修改" Object.assign(form, row) }
form
对象用于存储表单数据,当用户点击“修改”按钮时,toupdate
方法会被调用,它接收当前行的数据row
,并通过Object.assign
将当前行的数据复制到form
中,从而实现表单的回显。7.2 对话框的显示与标题变更:
// dialogTitle: 显示对话框标题,区分新增和修改 const dialogTitle = ref("新增")
和
// toadd: 显示新增分类的模态框,重置表单 const toadd = ()=>{ dialogTitle.value = "新增" } // toupdate: 显示修改分类的模态框,并将当前行数据填充到表单 const toupdate = (row)=>{ dialogTitle.value = "修改" }
dialogTitle
用来控制模态对话框的标题,初始化为"新增"。在toupdate
方法中,当用户点击修改时,标题会变更为"修改",以指示用户正在进行修改操作。在toadd
方法中,当用户点击修改时,标题会变更为"新增",以指示用户正在进行增加操作7.3 对话框的显示控制
// dialogFormVisible: 控制模态对话框的显示隐藏 const dialogFormVisible = ref(false)
和
const toadd = ()=>{ dialogFormVisible.value = true } // toupdate: 显示修改分类的模态框,并将当前行数据填充到表单 const toupdate = (row)=>{ dialogFormVisible.value = true }
dialogFormVisible
控制对话框的显示与隐藏。在toadd
和toupdate
方法中,通过改变其值为true
来显示对话框,从而开启新增或修改操作
8、如何实现新增清空数据
8.1 初始化表单数据
// form: 用于双向绑定表单输入的反应式对象,包含分类ID和名称 const form = reactive({ id: null, name:null, })
在脚本中,定义了
form
作为表单绑定的数据对象,,用于存储表单的当前状态// formInit: 用于保存表单的初始状态,便于重置表单 var formInit = reactive({})
formInit
是另一个响应式对象,用于存储表单的初始状态,以便在需要时可以重置表单8.2 复制
form
到formInit
onMounted(()=>{ refresh() Object.assign(formInit, form) })
将
form
的当前状态(此时为初始状态)复制到formInit
8.3 用toadd
函数以重置表单// toadd: 显示新增分类的模态框,重置表单 const toadd = ()=>{ dialogFormVisible.value = true dialogTitle.value = "新增" Object.assign(form, formInit) }
当调用
toadd
方法时,form
会被重置为formInit(初始状态),所有表单字段都会被清空,为新增商品分类准备了一个干净的表单