news 2026/4/15 15:49:39

bv-study05 vue基础(添加用户练习,最后附完整源码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
bv-study05 vue基础(添加用户练习,最后附完整源码)

一.要实现的功能展示

二.分步解决

1.vue2搭建

nodejs安装下载https://blog.csdn.net/weixin_55992854/article/details/121140754?spm=1001.2014.3001.5506

nvm安装下载

nvm安装教程

vue脚手架搭建

https://blog.csdn.net/qq_48164590/article/details/129440134

2.代码详解

2.1Vue 单文件组件(SFC)模板

<template>区域

<script>区域

<style scoped>区域

<template> 必须有且仅有一个根元素(如.component-container); 支持 Vue 核心指令:v-model(双向绑定)、v-for(循环)、v-if/v-show(条件渲染)、@事件名(事件绑定)等; 插值表达式{{ }}用于渲染响应式数据。 </template> <script> // 脚本区域:存放组件逻辑(数据、方法、生命周期等) export default { // 1. 组件名称(必填,建议 PascalCase 命名) name: 'BaseTemplate', // 2. 接收父组件传递的属性(可选) props: { // 示例:接收父组件传递的标题 title: { type: String, // 属性类型 default: '默认标题' // 默认值 } }, // 3. 响应式数据(核心) data() { return { // 组件内部标题(优先使用父组件传递的title) componentTitle: this.title, // 输入框绑定值 inputValue: '', // 其他自定义数据 count: 0 }; }, // 4. 计算属性(依赖数据自动更新,可选) computed: { // 示例:处理输入内容的长度 inputLength() { return this.inputValue.trim().length; } }, // 5. 监听属性(监听数据变化,可选) watch: { // 监听inputValue变化 inputValue(newVal, oldVal) { console.log('输入内容变化:', '新值=', newVal, '旧值=', oldVal); } }, // 6. 生命周期钩子(组件生命周期阶段执行,可选) created() { // 组件创建完成(数据已初始化,DOM未渲染) console.log('组件创建完成'); }, mounted() { // 组件挂载完成(DOM已渲染,可操作DOM) console.log('组件挂载完成'); }, // 7. 方法(业务逻辑处理,核心) methods: { /** * 按钮点击事件处理 */ handleClick() { this.count++; alert(`按钮点击了${this.count}次,输入内容长度:${this.inputLength}`); } } }; </script> <style scoped> /* 样式区域:组件样式,scoped表示样式仅作用于当前组件(避免污染) */ </style>

2.2 添加用户——

<template>区域 <!-- 姓名字段:必填,失去焦点触发姓名验证 --> <div class="form-item"> <label for="name"> <span class="point">*</span>姓名: </label> <input type="text" <!-- 文本输入框 --> id="name" <!-- 与label绑定,提升可访问性 --> v-model="user.name" <!-- 双向绑定到user对象的name属性 --> placeholder="请输入姓名" <!-- 占位提示 --> @blur="checkName" <!-- 失去焦点时触发姓名验证方法 --> style="margin-bottom: 10px;" <!-- 行内样式:底部间距 --> /> <!-- 姓名验证错误提示:nameEmpty为true时显示 --> <div v-if="nameEmpty" class="point" style="margin: 0 0 15px 60px;">请输入姓名</div>
<script>区域 // 数据定义:响应式数据 data() { return { // 新增/编辑用户的表单数据 user: { id: 0, // 用户ID(自增) name: '', // 姓名 age: '', // 年龄 email: '', // 邮箱 selected: false,// 复选框选中状态 edit: false, // 是否处于编辑状态 tmp: {} // 编辑时保存原始数据(用于取消编辑恢复) }, list: [], // 用户列表数组,存储所有用户数据 nameEmpty: false, // 姓名验证:是否为空 ageEmpty: false, // 年龄验证:是否为空/非法 emailEmpty: false,// 邮箱验证:是否格式错误 selected: [], // 选中行的索引数组(批量操作核心) selectedAll: false,// 全选框状态 num: 0 // 自增ID计数器,用于生成唯一用户ID }; }, method(){ addUser() { // 触发所有字段验证(确保提交时强制校验) this.checkName(); this.checkAge(); this.checkEmail(); // 若任意字段验证失败,终止方法 if (this.nameEmpty || this.ageEmpty || this.emailEmpty) return; // 校验姓名是否已存在(避免重复) if (this.list.some(item => item.name === this.user.name)) { alert('姓名已存在!'); return; } // 构造新用户对象(ID自增) const newUser = { id: ++this.num, // ID自增(每次新增+1) name: this.user.name, // 姓名 age: this.user.age, // 年龄 email: this.user.email,// 邮箱 selected: false, // 初始未选中 edit: false, // 初始非编辑状态 tmp: {} // 初始空对象(用于编辑缓存) }; // 将新用户添加到列表 this.list.push(newUser); // 重置表单(清空输入框+重置验证状态) this.resetForm(); // 提示添加成功 alert('添加成功!'); }, }
/** * 重置表单方法 * 1. 清空用户表单数据 * 2. 重置所有验证错误状态 */ resetForm() { this.user = { id: this.num, name: '', age: '', email: '', selected: false, edit: false, tmp: {} }; // 重置验证状态 this.nameEmpty = false; this.ageEmpty = false; this.emailEmpty = false; }, /** * 姓名验证方法(失去焦点触发) * 校验姓名是否为空(去除首尾空格) */ checkName() { this.nameEmpty = this.user.name.trim() === ''; }, /** * 年龄验证方法(失去焦点触发) * 1. 校验是否为空 * 2. 校验是否在0-120之间,非法则清空并标记错误 */ checkAge() { // 空值校验 if (this.user.age === '' || this.user.age <= 0 || this.user.age > 120) { this.ageEmpty = true; // 标记验证失败 this.user.age = ''; // 清空非法输入 } else { this.ageEmpty = false;// 验证通过 } }, /** * 邮箱验证方法(失去焦点触发) * 1. 使用正则校验邮箱格式 * 2. 去除首尾空格后校验,避免空格导致的误判 */ checkEmail() { // 邮箱正则表达式:匹配标准邮箱格式 const emailReg = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/; // 校验:空值/格式错误都标记为验证失败 this.emailEmpty = !emailReg.test(this.user.email.trim()); },

2.3 删除的相关方法

/** * 删除单行用户方法 * @param {Number} index - 当前行索引 * 1. 弹出确认框,取消则终止 * 2. 删除列表中对应行 * 3. 从选中数组移除当前索引(避免数据残留) */ deleteUser(index) { // 确认删除:用户取消则不执行后续逻辑 if (confirm('确定要删除该用户吗?')) { // splice删除:从index位置删除1个元素 this.list.splice(index, 1); // 从选中数组移除当前索引(避免后续批量操作出错) this.selected = this.selected.filter(i => i !== index); } }, /** * 批量删除选中用户方法 * 1. 校验是否有选中项,无则提示并终止 * 2. 确认删除,取消则终止 * 3. 倒序删除(避免索引错乱),清空选中状态 */ deleteSelected() { // 无选中项则提示并终止 if (this.selected.length === 0) { alert('请选择要删除的用户!'); return; } // 确认删除 if (confirm('确定要删除选中的用户吗?')) { // 倒序排序:避免正序删除导致索引错乱(核心!) // 例如选中[0,1],正序删0后,1变成0,再删1会删错行 this.selected.sort((a, b) => b - a).forEach(index => { this.list.splice(index, 1); // 逐个删除选中行 }); // 清空选中数组 this.selected = []; // 取消全选框状态 this.selectedAll = false; } }, /** * 删除所有用户方法 * 1. 校验列表是否为空,空则提示并终止 * 2. 确认删除,取消则终止 * 3. 清空列表,重置选中状态 */ deleteAll() { // 列表为空则提示 if (this.list.length === 0) { alert('暂无用户可删除'); return; } // 确认删除 if (confirm('确定要删除所有用户吗?')) { this.list = []; // 清空用户列表 this.selected = []; // 清空选中数组 this.selectedAll = false;// 取消全选框 } },

2.4 编辑的相关方法

/** * 编辑单行用户方法 * @param {Number} index - 当前行索引 * 1. 标记当前行为编辑状态 * 2. 缓存原始数据(用于取消编辑恢复) */ editUser(index) { const item = this.list[index]; item.edit = true; // 标记为编辑状态 // 缓存原始数据:避免编辑中取消时丢失原数据 item.tmp = { name: item.name, age: item.age, email: item.email }; }, /** * 保存编辑后的用户数据 * @param {Number} index - 当前行索引 * 1. 校验姓名:不能为空 * 2. 校验年龄:0-120之间 * 3. 校验邮箱:格式正确 * 4. 校验姓名:与其他行不重复(排除自身) * 5. 验证通过则退出编辑状态,清空缓存,提示成功 */ saveUser(index) { const item = this.list[index]; // 姓名不能为空(去除首尾空格) if (item.name.trim() === '') { alert('姓名不能为空!'); return; } // 年龄必须在0-120之间 if (item.age === '' || item.age < 0 || item.age > 120) { alert('请输入0-120之间的有效年龄!'); return; } // 邮箱格式校验 const emailReg = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/; if (!emailReg.test(item.email.trim())) { alert('请输入正确的邮箱格式!'); return; } // 校验姓名是否与其他行重复(排除当前行) const isDuplicate = this.list.some((i, idx) => idx !== index && i.name === item.name); if (isDuplicate) { alert('姓名已存在!'); return; } // 验证通过:退出编辑状态 item.edit = false; item.tmp = {}; // 清空缓存数据 alert('修改成功!'); // 提示修改成功 }, /** * 取消编辑方法 * @param {Number} index - 当前行索引 * 1. 退出编辑状态 * 2. 恢复缓存的原始数据 * 3. 清空缓存 */ cancelEdit(index) { const item = this.list[index]; item.edit = false; // 退出编辑状态 // 恢复原始数据(从tmp缓存中取) item.name = item.tmp.name; item.age = item.tmp.age; item.email = item.tmp.email; item.tmp = {}; // 清空缓存 }, editSelected() { // 无选中项则提示 if (this.selected.length === 0) { alert('请选择要修改的用户!'); return; } // 遍历选中行,逐个标记为编辑状态并缓存数据 this.selected.forEach(index => { const item = this.list[index]; item.edit = true; item.tmp = { name: item.name, age: item.age, email: item.email }; }); }

2.5 全选/单选的相关方法

/** * 全选/取消全选方法(全选框状态变化触发) * 1. 遍历列表,同步所有行的复选框状态 * 2. 更新选中索引数组:全选时生成所有索引,取消时清空 */ selectAll() { // 遍历列表,将所有行的selected同步为全选框状态 this.list.forEach((item) => { item.selected = this.selectedAll; }); // 更新选中索引数组:全选则生成所有索引,取消则清空 this.selected = this.selectedAll ? this.list.map((_, index) => index) // map生成索引数组[0,1,2...] : []; // 取消全选则清空 }, /** * 单行复选框状态变化方法 * @param {Number} index - 当前行索引 * 1. 获取当前行数据 * 2. 选中则添加索引(去重),取消则移除索引 * 3. 取消时同步取消全选框状态 */ handleCheckboxChange(index) { // 获取当前行的用户对象 const item = this.list[index]; // 复选框选中:添加索引到选中数组(避免重复) if (item.selected) { if (!this.selected.includes(index)) { this.selected.push(index); } } else { // 复选框取消:从选中数组移除当前索引 this.selected = this.selected.filter(i => i !== index); // 只要有一行取消,全选框必为未选中 this.selectedAll = false; } },

三.相关知识点汇总

一、模板语法(<template>核心)

1. 插值表达式{{ }}

  • 作用:渲染响应式数据到页面(文本渲染)
  • 案例对应{{ index + 1 }}(序号)、{{ item.name }}(用户名)
  • 注意:只能写表达式(如运算、方法调用),不能写语句(如if/for

2. 指令(Vue 特有的标签属性,以v-开头)

指令作用案例对应
v-model双向绑定(表单元素↔数据)v-model="user.name"v-model="item.selected"
v-for循环渲染列表v-for="(item, index) in list" :key="item.id"
v-if/v-else条件渲染(元素是否显示)v-if="!item.edit"v-if="list.length === 0"
@事件名绑定事件(简写,全称v-on@blur="checkName"@click="addUser"@change="selectAll"
:属性名绑定元素属性(简写,全称v-bind:key="item.id"(循环必须加唯一 key)

3. 关键细节

  • v-for必须加:key:用唯一值(如item.id),避免列表渲染错乱;
  • v-model适配不同表单类型:
    • 文本框 / 邮箱框:v-model="xxx"(字符串);
    • 数字框:v-model="xxx"(需校验数值类型);
    • 复选框:v-model="xxx"(布尔值 / 数组);
  • @blur(失去焦点):表单验证常用,避免实时校验干扰用户输入。

二、响应式数据(<script>核心)

1.data选项

  • 作用:定义组件内部的响应式数据;
  • 格式:必须是函数(返回对象),避免组件复用数据污染;
  • 案例对应

    js

    data() { return { user: { name: '', age: '' }, // 表单数据 list: [], // 列表数据 nameEmpty: false // 验证状态 }; }
  • 响应式特性:数据变化 → 页面自动更新(如this.nameEmpty = true会触发错误提示显示)。

2.methods选项

  • 作用:定义组件的业务方法(处理点击、验证、数据操作);
  • 案例对应
    • 事件处理:addUser()(新增)、deleteUser()(删除);
    • 表单验证:checkName()checkEmail()
    • 数据操作:selectAll()(全选)、saveUser()(保存编辑);
  • 关键:方法内通过this访问data中的数据(如this.listthis.user.name)。

3. 常用数组方法(列表操作核心)

方法作用案例对应
push()向数组末尾添加元素this.list.push(newUser)(新增用户)
splice()删除 / 替换数组元素this.list.splice(index, 1)(删除行)
filter()筛选数组(返回新数组)this.selected.filter(i => i !== index)(移除索引)
forEach()遍历数组this.list.forEach(item => { ... })(全选)
map()遍历数组并返回新数组this.list.map((_, index) => index)(生成索引数组)
some()检查是否有元素满足条件this.list.some(item => item.name === this.user.name)(姓名重复校验)

三、事件处理

1. 常用事件类型

事件名触发时机案例对应
click点击元素@click="addUser"
blur元素失去焦点@blur="checkName"
change表单元素值变化@change="selectAll"(复选框)

2. 事件传参

  • 无参:@click="addUser"→ 方法直接定义addUser() { ... }
  • 有参:@click="deleteUser(index)"→ 方法接收参数deleteUser(index) { ... }
  • 传事件对象:@input="handleInput($event)"→ 方法接收handleInput(e) { ... }

3. 核心逻辑:批量删除的「倒序删除」

  • 问题:正序删除列表元素会导致索引错乱(如删索引 0 后,原索引 1 变成 0);
  • 解决:this.selected.sort((a, b) => b - a).forEach(index => { ... })(先倒序,再删除)。

四、表单验证(实战重点)

1. 核心规则

  • 姓名:trim()去首尾空格,判断是否为空(this.user.name.trim() === '');
  • 年龄:校验数值范围(0-120),非法值清空并标记错误;
  • 邮箱:正则校验格式(/^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/);
  • 重复校验:some()检查列表中是否已存在相同姓名(排除自身)。

2. 验证时机

  • 失去焦点校验(@blur):提升用户体验;
  • 提交前强制校验:addUser()中先调用checkName()/checkAge()/checkEmail()

五、样式(<style scoped>

1.scoped作用

  • 样式仅作用于当前组件,避免全局样式污染;
  • 原理:Vue 自动为组件元素添加唯一属性,样式仅匹配该属性。

2. 常用样式技巧

  • 表单元素:统一边框、圆角、内边距,聚焦时修改边框色;
  • 按钮:hover状态修改背景色,cursor: pointer显示手型;
  • 表格:border-collapse: collapse合并边框,th加背景色区分表头。

六、Vue 基础高频问题

1. 为什么data是函数?

  • 组件复用时,每个实例拥有独立的数据源,避免数据共享导致的错乱(如多个用户列表组件共用一个list)。

2. 双向绑定原理?

  • v-model是语法糖:
    • 文本框:v-model="xxx":value="xxx" @input="xxx = $event.target.value"
    • 复选框:v-model="xxx":checked="xxx" @change="xxx = $event.target.checked"

3. 什么是响应式?

  • 数据变化 → Vue 自动更新页面(无需手动操作 DOM);
  • 注意:直接修改数组下标 / 对象属性(如this.list[0].name = 'xxx')是响应式的,但this.list[0] = { ... }需用Vue.set(Vue 2)。

4.labelinput绑定的意义?

  • label for="name"+input id="name"
    • 点击标签可聚焦输入框(提升操作体验);
    • 屏幕阅读器能识别标签与输入框的关联(提升可访问性)。

四.源代码

<template> <div> <div> <h2>添加用户</h2> <div class="form-item"> <label for="name"><span class="point">*</span>姓名:</label> <input type="text" id="name" v-model="user.name" placeholder="请输入姓名" @blur="checkName" style="margin-bottom: 10px;" /> </div> <div v-if="nameEmpty" class="point" style="margin: 0 0 15px 60px;">请输入姓名</div> <div class="form-item"> <label for="age"><span class="point">*</span>年龄:</label> <input type="number" id="age" v-model="user.age" placeholder="请输入年龄" @blur="checkAge" style="margin-bottom: 10px;" /> </div> <div v-if="ageEmpty" class="point" style="margin: 0 0 10px 60px;">请输入正确的年龄</div> <div class="form-item"> <label for="email"><span class="point">*</span>邮箱:</label> <input type="email" id="email" v-model="user.email" placeholder="请输入邮箱" @blur="checkEmail" style="margin-bottom: 10px;" /> </div> <div v-if="emailEmpty" class="point" style="margin: 0 0 10px 60px;">请输入正确的邮箱</div> <button @click="addUser" class="btn">提交</button> <button @click="resetForm" class="btn">重置</button> </div> <hr style="width: 700px; margin: 20px 0;"/> <div class="user-list"> <h2>用户列表</h2> <table class="user-table"> <thead> <tr> <th style="width: 23px;"> <input type="checkbox" v-model="selectedAll" @change="selectAll" class="all-check"/> </th> <th style="width: 23px;">序号</th> <th style="width: 80px;">姓名</th> <th style="width: 30px;">年龄</th> <th style="width: 120px;">邮箱</th> <th style="width: 80px;">操作</th> </tr> </thead> <tbody> <tr v-if="list.length === 0"> <td colspan="6" style="text-align: left;">暂无用户信息</td> </tr> <tr v-for="(item, index) in list" :key="item.id"> <td style="width: 23px;"> <input type="checkbox" v-model="item.selected" @change="handleCheckboxChange(index)" /> </td> <td style="width: 23px;">{{ index + 1 }}</td> <td style="width: 80px;"> <span v-if="!item.edit">{{ item.name }}</span> <input v-else type="text" v-model="item.name" style="width: 80px;"/> </td> <td style="width: 30px;"> <span v-if="!item.edit">{{ item.age }}</span> <input v-else type="number" v-model="item.age" style="width: 30px;"/> </td> <td style="width: 120px;"> <span v-if="!item.edit">{{ item.email }}</span> <input v-else type="text" v-model="item.email" style="width: 120px;"/> </td> <td style="width: 80px;"> <button @click="editUser(index)" v-if="!item.edit" class="btn">修改</button> <button @click="saveUser(index)" v-else class="btn">保存</button> <button @click="deleteUser(index)" v-if="!item.edit" class="btn">删除</button> <button @click="cancelEdit(index)" v-else class="btn">取消</button> </td> </tr> <tr> <td colspan="6"> <button @click="deleteAll" class="btn">删除所有</button> <button @click="deleteSelected" class="btn">批量删除</button> <button @click="editSelected" class="btn">批量修改</button> </td> </tr> </tbody> </table> </div> </div> </template> <script> export default { name: 'UserManager', data() { return { user: { id: 0, name: '', age: '', email: '', selected: false, edit: false, tmp: {} }, list: [], nameEmpty: false, ageEmpty: false, emailEmpty: false, selected: [], selectedAll: false, num: 0 }; }, methods: { addUser() { this.checkName(); this.checkAge(); this.checkEmail(); if (this.nameEmpty || this.ageEmpty || this.emailEmpty) return; if (this.list.some(item => item.name === this.user.name)) { alert('姓名已存在!'); return; } const newUser = { id: ++this.num, name: this.user.name, age: this.user.age, email: this.user.email, selected: false, edit: false, tmp: {} }; this.list.push(newUser); this.resetForm(); alert('添加成功!'); }, resetForm() { this.user = { id: this.num, name: '', age: '', email: '', selected: false, edit: false, tmp: {} }; this.nameEmpty = false; this.ageEmpty = false; this.emailEmpty = false; }, checkName() { this.nameEmpty = this.user.name.trim() === ''; }, checkAge() { if (this.user.age === '' || this.user.age <= 0 || this.user.age > 120) { this.ageEmpty = true; this.user.age = ''; } else { this.ageEmpty = false; } }, checkEmail() { const emailReg = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/; this.emailEmpty = !emailReg.test(this.user.email.trim()); }, selectAll() { this.list.forEach((item) => { item.selected = this.selectedAll; }); this.selected = this.selectedAll ? this.list.map((_, index) => index) : []; }, handleCheckboxChange(index) { const item = this.list[index]; if (item.selected) { if (!this.selected.includes(index)) { this.selected.push(index); } } else { this.selected = this.selected.filter(i => i !== index); this.selectedAll = false; } }, deleteUser(index) { if (confirm('确定要删除该用户吗?')) { this.list.splice(index, 1); this.selected = this.selected.filter(i => i !== index); } }, deleteSelected() { if (this.selected.length === 0) { alert('请选择要删除的用户!'); return; } if (confirm('确定要删除选中的用户吗?')) { this.selected.sort((a, b) => b - a).forEach(index => { this.list.splice(index, 1); }); this.selected = []; this.selectedAll = false; } }, deleteAll() { if (this.list.length === 0) { alert('暂无用户可删除'); return; } if (confirm('确定要删除所有用户吗?')) { this.list = []; this.selected = []; this.selectedAll = false; } }, editUser(index) { const item = this.list[index]; item.edit = true; item.tmp = { name: item.name, age: item.age, email: item.email }; }, saveUser(index) { const item = this.list[index]; if (item.name.trim() === '') { alert('姓名不能为空!'); return; } if (item.age === '' || item.age < 0 || item.age > 120) { alert('请输入0-120之间的有效年龄!'); return; } const emailReg = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/; if (!emailReg.test(item.email.trim())) { alert('请输入正确的邮箱格式!'); return; } const isDuplicate = this.list.some((i, idx) => idx !== index && i.name === item.name); if (isDuplicate) { alert('姓名已存在!'); return; } item.edit = false; item.tmp = {}; alert('修改成功!'); }, cancelEdit(index) { const item = this.list[index]; item.edit = false; item.name = item.tmp.name; item.age = item.tmp.age; item.email = item.tmp.email; item.tmp = {}; }, editSelected() { if (this.selected.length === 0) { alert('请选择要修改的用户!'); return; } this.selected.forEach(index => { const item = this.list[index]; item.edit = true; item.tmp = { name: item.name, age: item.age, email: item.email }; }); } } }; </script> <style scoped> .point { color: red; font-size: 12px; margin-right: 5px; } .form-item { margin: 3px 0; font-size: 14px; } input { border: 1px solid #ccc; border-radius: 4px; height: 22px; padding: 0 5px; } input:focus { outline: none; border-color: #999; } .btn { margin: 0 5px 5px 0; padding: 5px 10px; border: 1px solid #ccc; border-radius: 4px; background-color: #f5f5f5; cursor: pointer; } .btn:hover { background-color: #bfbcbc; } .user-table { border-collapse: collapse; width: 700px; margin-top: 10px; } .user-table th, .user-table td { border: 1px solid #ccc; padding: 8px; text-align: left; } .user-table th { background-color: #f5f5f5; font-weight: bold; } </style>
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/13 15:32:00

如何快速掌握猫抓资源嗅探器:新手必备的完整使用指南

猫抓资源嗅探器是一款专为浏览器设计的智能媒体捕获工具&#xff0c;能够自动识别网页中的视频、音频和图片资源&#xff0c;为普通用户提供简单高效的下载管理体验。无论您是想保存社交媒体视频、在线课程内容还是网页图片&#xff0c;这款免费工具都能完美胜任。 【免费下载链…

作者头像 李华
网站建设 2026/4/13 22:40:07

session和cookie的区别

Session的工作原理Session是一种服务器端的机制&#xff0c;用于跟踪用户的状态和数据。当用户首次访问网站时&#xff0c;服务器会创建一个唯一的Session ID&#xff0c;并通过Cookie或URL重写的方式将该ID发送给客户端。客户端在后续请求中会携带这个Session ID&#xff0c;服…

作者头像 李华
网站建设 2026/4/5 9:36:33

海外网红推广中的品牌声誉保护与危机处理机制

随着品牌出海规模不断扩大&#xff0c;海外网红推广已成为企业触达全球消费者最直接、最高效的方式之一。然而&#xff0c;红人合作的开放性、舆论传播的不可控性、跨文化解读的复杂性&#xff0c;使得品牌声誉保护成为企业在全球营销中的首要挑战。如果品牌缺乏稳固的危机处理…

作者头像 李华
网站建设 2026/4/15 15:49:33

基于.Net 8创建 CAD勘测定界图(三)——界址点标注+边长标注

好的&#xff0c;之前的两篇文章大概介绍了一下关于做这个功能的背景和关于Aspose.CAD For .Net填充无效&#xff0c;转用ACadSharp创建红线和界址点符号的内容&#xff0c;具体看&#xff1a; 基于.Net 8创建 CAD勘测定界图&#xff08;一&#xff09; 基于.Net 8创建 CAD勘测…

作者头像 李华
网站建设 2026/4/13 10:11:27

Qwen3-VL-235B-A22B:2025多模态AI革命,从看懂到行动的跨越

Qwen3-VL-235B-A22B&#xff1a;2025多模态AI革命&#xff0c;从看懂到行动的跨越 【免费下载链接】Qwen3-VL-235B-A22B-Instruct 项目地址: https://ai.gitcode.com/hf_mirrors/Qwen/Qwen3-VL-235B-A22B-Instruct 导语 阿里通义千问团队推出的Qwen3-VL-235B-A22B-Ins…

作者头像 李华
网站建设 2026/4/5 15:09:31

DiT模型压缩实战:从实验室到边缘设备的智能部署方案

DiT模型压缩实战&#xff1a;从实验室到边缘设备的智能部署方案 【免费下载链接】DiT Official PyTorch Implementation of "Scalable Diffusion Models with Transformers" 项目地址: https://gitcode.com/GitHub_Trending/di/DiT 你是否曾经为运行大型AI模型…

作者头像 李华