-
在 Vue 中,v-if 和 v-bind:disabled(或简写 :disabled)都可以控制元素的行为,但它们的作用机制和使用场景有本质区别。以下是详细对比:1. 作用目标不同v-if控制整个元素的存在性:直接决定是否渲染该 DOM 元素(从虚拟 DOM 中添加/移除)。示例:<button v-if="isShow">Submit</button> 当 isShow 为 false 时,<button> 不会出现在 DOM 中。:disabled控制元素的特定属性:仅修改元素的 disabled 属性(元素始终存在,只是禁用状态变化)。示例:<button :disabled="isDisabled">Submit</button> 当 isDisabled 为 true 时,按钮会变为禁用状态(但仍可被看到)。2. 性能影响v-if切换成本高:因为会触发元素的完整销毁和重新创建(包括子组件的生命周期钩子)。适合不频繁切换的场景:例如根据权限显示/隐藏整个模块。:disabled切换成本低:仅修改属性,不会影响 DOM 结构或生命周期。适合频繁状态变化:如表单按钮在输入验证时的动态禁用。3. 副作用差异v-if子组件状态丢失:如果被移除的元素内部有子组件,切换时会完全销毁并重建子组件(状态重置)。事件监听器移除:元素的事件监听器也会被移除。:disabled保留元素状态:即使禁用,元素仍存在于 DOM 中,内部状态(如输入框的值)不会丢失。事件仍可触发:但浏览器会阻止禁用元素的默认行为(如点击事件)。4. 使用场景对比场景推荐指令原因根据条件显示/隐藏整个模块v-if避免不必要的 DOM 节点存在(如管理员专属功能)。表单提交按钮的动态禁用:disabled频繁切换禁用状态(如表单验证中),无需重建 DOM。条件性渲染大型组件v-if避免隐藏的复杂组件占用内存或触发不必要的计算。临时禁用交互元素:disabled需要保留元素状态(如输入框内容),同时阻止用户操作。5. 代码示例对比v-if 控制存在性<template> <div> <button v-if="isAdmin">Delete</button> </div> </template> <script> export default { data() { return { isAdmin: false }; } }; </script> 当 isAdmin 为 false 时,<button> 完全不存在于 DOM 中。:disabled 控制状态<template> <div> <button :disabled="!isValid">Submit</button> </div> </template> <script> export default { data() { return { isValid: false }; } }; </script> 按钮始终存在,但根据 isValid 切换禁用状态。6. 组合使用两者可以结合使用,实现更精细的控制:<button v-if="user.isLoggedIn" :disabled="isSubmitting" > {{ isSubmitting ? 'Submitting...' : 'Submit' }} </button> <button v-else @click="login"> Please Login </button> 登录后显示按钮,提交时禁用按钮。总结特性v-if:disabled作用目标整个元素的存在性元素的 disabled 属性DOM 操作添加/移除元素仅修改属性性能切换成本高切换成本低子组件状态销毁后重置保留状态适用场景条件性渲染模块动态禁用交互元素根据需求选择:需要彻底隐藏元素 → v-if仅需禁用交互但保留元素 → :disabled
-
在 Vue 中,<div :id="\list-${id}`">是一个动态绑定idattribute 的示例,使用了 **JavaScript 的模板字符串(Template Literals)** 和 **Vue 的v-bind 缩写(:`)**。下面逐步解析它的含义和用法:1. v-bind 缩写 ::id 是 v-bind:id 的简写,表示将 id attribute 与 Vue 实例中的数据动态绑定。例如,如果 id 的值是 123,最终渲染的 HTML 会是 <div id="list-123"></div>。2. 模板字符串 `list-${id}`这是 ES6 的模板字符串语法,用反引号(`)包裹字符串,并通过 ${expression} 嵌入动态值。在 Vue 的模板中,可以直接在 :attribute 绑定中使用 JavaScript 表达式,因此模板字符串会被动态计算。3. 代码解析<div :id="\`list-\${id}\`"></div> id 的来源:假设 Vue 实例的 data 中定义了 id:data() { return { id: 'item-1' // 可以是字符串、数字等 } } 渲染结果:如果 id 是 "item-1",最终渲染为:<div id="list-item-1"></div> 如果 id 是 42,渲染为:<div id="list-42"></div> 4. 为什么用模板字符串?动态拼接字符串:直接在绑定中组合静态文本("list-")和动态数据(id)。可读性:比传统字符串拼接(如 'list-' + id)更简洁。支持复杂表达式:模板字符串内可以嵌入任意有效的 JavaScript 表达式,例如:<div :id="\`list-\${id}-\${index}\`"></div> 5. 等价写法使用字符串拼接(ES5 语法):<div :id="'list-' + id"></div> 使用计算属性(适合复杂逻辑):<div :id="computedId"></div> computed: { computedId() { return `list-${this.id}`; } } 6. 注意事项数据类型:id 可以是字符串或数字,但如果是其他类型(如对象、数组),需要确保转换为字符串(Vue 会自动调用 .toString())。特殊字符:如果 id 包含可能破坏 HTML 结构的字符(如空格、引号),需用 encodeURIComponent 处理:<div :id="\`list-\${encodeURIComponent(id)}\`"></div> 总结作用:动态生成 id attribute,格式为 list-{id}。关键点:: 是 v-bind 的缩写,用于动态绑定 attribute。反引号 ` 是 ES6 模板字符串,支持 ${} 嵌入变量。最终结果是静态文本("list-")和动态数据(id)的拼接。这种写法在需要生成唯一 ID 或动态类名、样式时非常常见(例如列表项、表单元素等)。
-
官网中有这样一段话当 isButtonDisabled 为真值或一个空字符串 (即 <button disabled="">) 时,元素会包含这个 disabled attribute。而当其为其他假值时 attribute 将被忽略。关于布尔型 attribute(如 disabled、readonly、checked 等)在 HTML 和 Vue 中的行为,确实有一些需要澄清的设计逻辑。1. HTML 标准中的布尔型 Attribute在原生 HTML 中,布尔型 attribute 的存在即代表 true,其值本身无关紧要。例如:<button disabled>Button</button> <!-- 等价于 disabled="disabled" --> <input type="checkbox" checked> <!-- 等价于 checked="checked" --> 即使你写成:<button disabled="">Button</button> <!-- 空字符串值 --> <button disabled="false">Button</button> <!-- 字符串 "false" --> 浏览器仍然会将其视为 true,因为只要 attribute 存在,就是启用状态。唯一移除布尔型 attribute 的方式是直接删除它。2. Vue 的 v-bind 行为设计Vue 的 v-bind 在处理布尔型 attribute 时,模拟了 HTML 的这种行为:当绑定的值为 真值(true、非空字符串、对象、数组等)或空字符串时,Vue 会渲染该 attribute。当值为 假值(false、null、undefined、0)时,Vue 会移除该 attribute。为什么空字符串 ("") 也算作“真”?这是为了兼容 HTML 的惯用写法。在原生 HTML 中,开发者可能会这样写:<button :disabled="someCondition ? 'disabled' : ''"> 如果 Vue 将空字符串视为假值,这种写法会失效(attribute 被移除)。因此,Vue 选择将空字符串视为“需要保留 attribute”的信号,从而保持与模板中硬编码 disabled="" 的一致性。对比其他假值false、null、undefined:明确表示“不需要 attribute”,因此 Vue 会移除它。0:虽然是数字,但在布尔上下文中属于假值,也会移除 attribute(但像 maxlength="0" 这样的非布尔 attribute 可能需要特殊处理)。3. 设计背后的考量与 HTML 习惯一致开发者可能已经习惯在模板中写 disabled="",Vue 的设计避免了意外行为。灵活性允许通过动态绑定(如 :disabled="someStringVar")控制 attribute 的存在,而无需严格限制为布尔值。明确性如果希望移除 attribute,应显式使用 false、null 或 undefined,而不是依赖空字符串的隐式转换。4. 如何避免混淆?显式使用布尔值:推荐在脚本中使用明确的布尔值,提高可读性:<button :disabled="isButtonDisabled">Button</button> data() { return { isButtonDisabled: true // 或 false } } 需要移除 attribute 时:确保绑定值为 false 而非空字符串:<button :disabled="shouldDisable ? true : false">Button</button> <!-- 或更简洁的 --> <button :disabled="!!someCondition">Button</button> 总结空字符串 ("") 被视为真值:这是为了兼容 HTML 中 disabled="" 的常见写法。假值包括:false、null、undefined、0(以及 NaN 等)。最佳实践:在脚本中显式使用布尔值,避免依赖空字符串的隐式行为。这种设计虽然初看有些反直觉,但目的是为了与 HTML 的惯用模式保持一致,并提供更灵活的动态绑定。
-
Vue 官网中有这么一句话注意,你不能使用 v-html 来拼接组合模板,因为 Vue 不是一个基于字符串的模板引擎。在使用 Vue 时,应当使用组件作为 UI 重用和组合的基本单元。这两句话强调了 Vue 的设计理念和最佳实践,核心在于 避免直接操作 HTML 字符串,而是通过 组件化 的方式构建 UI。以下是详细解释:1. “你不能使用 v-html 来拼接组合模板”含义:v-html 是 Vue 的指令,用于将数据作为 HTML 字符串动态渲染到 DOM 中(类似 innerHTML)。问题:如果用 v-html 拼接模板片段(例如通过字符串拼接或动态生成 HTML),会破坏 Vue 的响应式系统和组件化优势。示例(反模式):<template> <div v-html="dynamicTemplate"></div> </template> <script>export default { data() { return { dynamicTemplate: '<div>' + someVariable + '</div><button>' + anotherVar + '</button>' }; } }; </script> 为什么不好?安全性风险:直接渲染 HTML 字符串可能导致 XSS 攻击(如果字符串来自用户输入且未转义)。失去响应性:动态 HTML 中的变量不会自动更新,因为 Vue 无法追踪字符串内部的动态绑定。难以维护:模板逻辑与 JavaScript 代码混杂,违背关注点分离原则。2. “Vue 不是一个基于字符串的模板引擎”含义:Vue 的模板是 声明式的(基于 DOM 结构或虚拟 DOM),而非通过字符串拼接生成 HTML。对比 jQuery 或旧式框架(如 Backbone),Vue 不鼓励手动操作 DOM 字符串,而是通过数据驱动视图。正确做法:使用 Vue 的模板语法(如 {{ }}、v-if、v-for)或 组件 来组合 UI。示例(正确方式):<template> <div> <div>{{ someVariable }}</div> <button>{{ anotherVar }}</button> </div> </template> 或通过组件组合:<template> <CustomComponent :title="someVariable" /> </template> 3. “应当使用组件作为 UI 重用和组合的基本单元”含义:组件化 是 Vue 的核心思想。将 UI 拆分为独立的、可复用的组件,每个组件封装自己的模板、逻辑和样式。优势:可复用性:组件可以在不同地方复用。可维护性:每个组件职责单一,便于调试和扩展。响应式:数据变化自动更新视图,无需手动操作 DOM。示例:<!-- 定义组件 --> <template> <div class="card"> <h2>{{ title }}</h2> <p>{{ content }}</p> </div> </template> <script>export default { props: ['title', 'content'] }; </script> <!-- 复用组件 --> <template> <Card title="Hello" content="This is a reusable component." /> <Card title="World" content="Another instance." /> </template> 总结避免:用 v-html 拼接模板字符串(如 v-html="'<div>' + data + '</div>'")。推荐:使用 Vue 的模板语法或组件化开发,让 Vue 管理 DOM 和数据绑定。根本原因:Vue 的核心是 响应式数据绑定 + 虚拟 DOM,而非字符串模板操作。组件化能充分利用这一优势,同时提升代码质量和安全性。如果需要动态渲染内容,优先使用:模板语法(如 {{ }}、v-if)。动态组件(<component :is="...">)。渲染函数/JSX(高级场景)。
-
在 Vue 3 中,**应用实例(App Instance)和根组件实例(Root Component Instance)**是两个不同的概念,它们在应用启动过程中扮演不同的角色。以下是它们的详细解释和区别:1. 应用实例(App Instance)创建方式:通过 Vue.createApp() 创建。const app = Vue.createApp({ /* 根组件选项 */ }); 作用:作为应用的入口,用于全局配置和注册资源(如组件、指令、插件等)。提供全局方法(如 app.use()、app.component()、app.directive())。是整个 Vue 应用的上下文,所有子组件的祖先。特点:一个应用实例可以挂载多个根组件(但通常只挂载一个)。本身不直接参与渲染,而是通过 mount() 方法与 DOM 关联。2. 根组件实例(Root Component Instance)创建方式:通过调用应用实例的 .mount() 方法时自动创建。const rootComponentInstance = app.mount('#app'); 作用:是应用的最顶层组件实例,其他所有组件都是它的后代。作为渲染的起点,Vue 会从根组件开始递归渲染整个组件树。特点:.mount() 的返回值是根组件实例(而非应用实例)。可以通过它访问根组件的属性和方法(如 rootComponentInstance.$data)。通常不需要手动操作它,除非需要直接控制根组件。关键区别特性应用实例(App Instance)根组件实例(Root Component Instance)创建方式Vue.createApp()调用 app.mount() 时自动创建返回值自身(app)根组件实例用途全局配置、注册资源作为渲染入口,管理组件树访问方式直接通过 app 变量通过 app.mount() 的返回值示例代码// 1. 创建应用实例 const app = Vue.createApp({ data() { return { message: "Hello Vue!" }; } }); // 2. 注册全局资源(应用实例的方法) app.component('MyComponent', { /* ... */ }); // 3. 挂载应用,获取根组件实例 const rootComponentInstance = app.mount('#app'); console.log(app); // 应用实例 console.log(rootComponentInstance); // 根组件实例(包含根组件的 data、methods 等) 为什么需要区分?应用实例用于配置和扩展应用(如插件、全局组件)。根组件实例用于直接操作渲染后的组件(如访问根组件的 $data 或 $el),但通常推荐通过模板或状态管理(如 Pinia)间接操作数据。正确理解这两者的区别,可以避免在需要应用实例时误用根组件实例(例如错误地尝试在根组件实例上调用 app.use())。
-
在 Vue 3 的 <script setup> 语法中,const count = ref(0) 使用 const 声明响应式变量是 完全合理 的,尽管 count 看起来像是一个“变量”(可以修改)。这涉及到 JavaScript 的 const 和 Vue 的响应式系统的特性,以下是详细解释:1. const 的真正含义const 声明的变量 不能被重新赋值(即不能对变量本身重新指向另一个值),但 变量指向的对象/数组/响应式引用的内部状态是可以修改的。const arr = [1, 2, 3]; arr.push(4); // 允许:修改数组内容 arr = [5, 6]; // 报错:不能重新赋值 在 Vue 的 ref 示例中:const count = ref(0); // count 是一个 Ref 对象 count.value++; // 允许:修改 Ref 对象的 .value 属性 count = 42; // 报错:不能对 count 重新赋值 count 本身是一个 Ref 对象(通过 ref() 创建),它的引用地址不可变(const 的约束)。但通过 count.value 可以修改其内部存储的值(Vue 的响应式系统会跟踪这种变化)。2. 为什么 Vue 推荐用 const 声明响应式变量?语义明确:const 表示“这个变量不会被重新赋值”,而响应式变量(如 ref 或 reactive)的引用本身确实不应该被修改(否则会破坏响应性)。避免意外错误:如果误写 count = newValue(而不是 count.value = newValue),const 会直接报错,帮助你快速发现问题。与普通变量的区别:在非响应式场景中,用 let 声明普通变量更合适(因为变量值可能被重新赋值)。但在 Vue 的响应式系统中,我们通常 只修改 .value,而不修改引用本身。3. 对比 let 和 const 的使用场景场景推荐声明方式原因响应式变量(ref)const避免意外重新赋值,强调“引用不可变,但内部值可变”。普通变量let变量值可能被重新赋值(如循环计数器、临时状态)。真正的常量const固定不变的配置(如 const API_URL = "https://api.example.com")。4. 深入 ref 的机制ref(0) 返回的是一个 对象(RefImpl 实例),结构如下:{ value: 0 } const count = ref(0) 只是将 count 绑定到这个对象,后续通过 count.value 修改值,而不是修改 count 本身。5. 如果用 let 会怎样?虽然可以用 let,但 没有意义,反而可能引发误用:let count = ref(0); count = 42; // 错误!丢失了响应性,因为 count 不再是 Ref 对象 用 let 不会报错,但你会意外破坏响应式引用,导致 UI 不更新。const 能强制你通过 count.value 修改值,避免这种错误。总结const + ref 是 Vue 3 的最佳实践,强调“响应式引用不可变,但内部值可变”。不要混淆 const 的“不可变”与响应式变量的“可变性”:前者针对变量引用,后者针对 .value。如果尝试直接对 const 声明的响应式变量重新赋值(如 count = newValue),JavaScript 会报错,这正是我们想要的安全约束。这种设计既利用了 JavaScript 的语言特性,又与 Vue 的响应式系统完美契合!
-
在 Web 前端开发中,如何高效、准确地将数据变化同步到用户界面(UI),是所有框架必须解决的核心问题。这一机制被称为响应式系统(Reactivity System)。从 AngularJS 的脏检查,到 Vue 的依赖追踪,再到 SolidJS 和 Svelte 的编译时响应式,响应式模型的演进不仅极大提升了应用性能,也深刻改变了开发者的心智模型。一、响应式系统的本质目标响应式系统需解决两个关键问题:依赖收集(Dependency Collection)当组件渲染时,自动记录它读取了哪些状态变量。变更触发(Change Propagation)当状态变量更新时,精准通知所有依赖它的 UI 部分重新计算或渲染。理想情况下,系统应做到:无遗漏:所有依赖都被捕获无冗余:无关状态变更不触发更新低开销:依赖收集与触发的性能损耗极小二、第一代:脏检查(Dirty Checking)—— AngularJS 的探索AngularJS(2010)采用脏检查(Dirty Checking) 机制:维护一个 $watch 列表,记录所有需要监听的表达式每次事件(如点击、HTTP 回调)后,进入 $digest 循环循环遍历所有 watcher,比较新旧值,若变化则执行回调循环持续至所有值稳定(最多 10 轮,防死循环)缺陷明显:性能差:O(n) 复杂度,watcher 过多时卡顿严重无法检测隐式变更:如 arr.push() 不会触发检查(需手动调用 $apply)调试困难:变更来源不透明📌 历史意义:首次将“数据驱动视图”理念大规模落地,但机制原始。三、第二代:基于 Proxy/Getter 的运行时响应式 —— Vue 与 MobX为克服脏检查缺陷,Vue 2/3 和 MobX 引入运行时依赖追踪。1. Vue 2:Object.defineProperty递归遍历 data 对象,将每个属性转为 getter/settergetter 中收集依赖(当前组件的 watcher)setter 中触发更新// 简化版 Vue 2 响应式function defineReactive(obj, key, val) { Object.defineProperty(obj, key, { get() { dep.depend(); // 收集当前 watcher return val; }, set(newVal) { if (newVal !== val) { val = newVal; dep.notify(); // 通知更新 } } });}局限:无法监听新增/删除属性(需 Vue.set)数组变异方法需重写(push, splice 等)2. Vue 3:Proxy + Reflect使用 ES6 Proxy 拦截整个对象自动支持动态属性、数组索引变更通过 effect 函数包裹渲染逻辑,自动追踪依赖const state = reactive({ count: 0 });effect(() => { console.log(state.count); // 自动收集依赖});state.count++; // 触发 effect 重新执行3. MobX:更灵活的响应式使用 observable 标记状态,autorun 包裹副作用支持任意 JavaScript 对象(无需预定义结构)依赖追踪粒度精确到属性访问四、第三代:编译时响应式 —— Svelte 与 SolidJS 的革命为彻底消除运行时开销,Svelte 和 SolidJS 将响应式逻辑移至编译阶段。1. Svelte:编译为精准更新指令Svelte 编译器分析模板中的变量使用生成仅更新相关 DOM 的 JavaScript 代码无虚拟 DOM,无 diff,无响应式运行时库<!-- App.svelte --><script> let count = 0;</script><button on:click={() => count++}> {count}</button>编译后(简化):function instance($$self, $$props, $$invalidate) { let count = 0; const click_handler = () => $$invalidate(0, count++); return [count, click_handler];}// 更新时直接操作 DOMp(ctx, [dirty]) { if (dirty & /*count*/ 1) { set_data(t0, ctx[0]); }}2. SolidJS:Signals + 编译优化引入 Signal 原语:createSignal() 返回 getter/setter编译器识别 JSX 中的 Signal 调用,自动包裹 createEffect更新时直接操作真实 DOM,无 VDOM diffconst [count, setCount] = createSignal(0);return <button onClick={() => setCount(c => c + 1)}>{count()}</button>;编译后,count() 的调用被识别为依赖,自动建立响应关系。核心优势:零运行时响应式开销:无 Proxy,无递归 defineProperty更新粒度极致精细:仅变更的文本节点被更新包体积小:SolidJS 运行时仅 ~7KB
-
一、什么是前端工程化?前端工程化是指通过工具链、规范流程和自动化手段,将前端开发从“手工劳动”转变为“标准化生产”的过程。其核心目标包括:提升开发体验(DX)保证代码质量与一致性优化构建与部署效率实现可维护、可扩展的架构二、现代前端工程化核心组件1. 包管理与依赖治理工具:npm / Yarn / pnpm最佳实践:使用 pnpm 减少磁盘占用与安装时间(通过硬链接 + 符号链接共享依赖)锁定版本(package-lock.json 或 pnpm-lock.yaml)定期审计漏洞:npm audit 或 yarn audit 示例:pnpm 在 monorepo 项目中表现尤为出色,支持 workspace 协议实现本地包引用。2. 模块化与构建工具过去依赖 <script> 标签的时代已终结,如今主流方案包括:工具特点适用场景Vite基于 ES Modules 原生加载,启动快如闪电新项目首选,React/Vue/Svelte 全支持Webpack插件生态丰富,配置灵活复杂定制需求、遗留项目迁移esbuild / SWC极速编译(Go/Rust 编写)构建加速、替代 Babel/TSC 推荐:新项目优先选择 Vite + TypeScript + ESLint + Prettier 组合。3. 代码质量保障体系静态检查ESLint:统一代码风格,禁止危险写法(如 ==、var)TypeScript:静态类型检查,减少运行时错误Stylelint:CSS/SCSS 规范校验自动格式化Prettier:一键格式化,终结团队“缩进之争”提交前校验// package.json{ "scripts": { "lint": "eslint src --ext .ts,.tsx", "type-check": "tsc --noEmit", "prepare": "husky install" }}配合 Husky + lint-staged,实现 git commit 时自动修复并校验变更文件。4. 组件化与设计系统使用 Storybook 或 Chromatic 独立开发、测试、文档化 UI 组件建立团队共享的 Design Token(颜色、间距、字体等)推行 Atomic Design 方法论(Atoms → Molecules → Organisms)5.CI/CD 与自动化部署典型 GitHub Actions 流水线:name: CI/CDon: [push]jobs: build-and-deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v2 - run: pnpm install - run: pnpm lint - run: pnpm test:unit - run: pnpm build - name: Deploy to Vercel run: npx vercel --prod --token ${{ secrets.VERCEL_TOKEN }}支持预发环境(Preview Deployment)、自动回滚、性能监控(Lighthouse CI)等能力。三、不止于“快”工程化最终要服务于用户体验:代码分割(Code Splitting):按路由或组件懒加载资源压缩:Brotli 替代 Gzip,体积再降 15%缓存策略:Immutable Caching + 内容哈希(如 [name].[hash].js)性能监控:集成 Sentry、Web Vitals(FCP, LCP, CLS) 前端工程化不是堆砌工具,而是围绕“人”与“价值”构建高效、可靠、可持续的开发闭环
-
案例介绍本项目是基于华为开发者空间云上开发环境部署的 RuoYi-Vue + TinyAgent + MCP + MaaS 技术实践案例。该应用在 RuoYi-Vue 中深度集成华为云MaaS(ModelArts as a Service)平台提供的DeepSeek大语言模型,并使用 TinyAgent 对接 MCP 服务,充分利用平台提供的百万级商用 Token 处理能力以及 Agent 技术,探索传统前端项目的智能化改造。案例内容一、概述1. 案例介绍本项目通过结合 RuoYi-Vue 的前端框架、华为云 MaaS 提供的大语言模型服务、TinyAgent 的智能代理能力以及 MCP 服务,实现了一个高效的智能化系统。该系统可以快速部署在开发环境中,提供高性能的智能对话服务,并通过智能代理进行业务自动化处理。应用中,RuoYi-Vue 作为前端框架提供了灵活的界面设计和快速开发的能力,配合 DeepSeek 模型的强大语言处理能力,使得本应用能够支持自然语言理解、对话管理和语义分析等多种功能。TinyAgent 通过接入 MCP 服务,进一步增强了系统的智能化水平,使得应用在面对复杂场景时,能够更好地处理多轮对话和长文本分析任务。该项目不仅为企业和个人开发者提供了一个智能化改造的范例,也为高校学生提供了实践机会,让他们能够深入了解前端开发、智能对话系统、Agent 技术以及云平台应用的结合。2. 适用对象企业个人开发者高校学生## 3. 案例时间本案例总时长预计60分钟。## 4. 案例流程说明:注册登录华为开发者空间,进入云开发环境(容器)平台,web端实现容器的创建与开机操作;PC本地通过VS Code安装Huawei Developer Space插件,远程连接操作云开发环境(容器)的;领取百万token代金券福利,登录MaaS平台,开通商用模型服务,获取模型调用参数API Key;GitCode拉取 RouYi-Vue + TinyAgent 改造代码,安装依赖,修改配置参数API Key,运行 MCP Server 端;启动程序,在浏览器端测试验证,通过 AIChat 操作页面功能。5. 资源总览本案例预计花费0元。资源名称规格单价(元)时长(分钟)华为开发者空间开发平台 - 云开发环境(容器)鲲鹏通用计算增强型 kc1 | 2vCPUs | 4G | HCE免费60二、基础环境与资源准备1. VS Code远程连接云开发环境容器参考案例《华为开发者空间 - 云开发环境(容器)IDE插件远程连接操作指导》中的“二、云开发环境IDE插件远程连接操作指导”的内容,完成“1. 安装插件” ~ “4. 连接”章节步骤。我这里选择的 All in One 环境,也就是包括了 NodeJS、Java、Python、Go 的环境。完成连接之后的状态:2. 领取百万免费token福利参考案例《Versatile Agent中自定义接入大模型配置华为云Maas指导》中的“一、 领取”章节内容,领取华为开发者空间百万token代金券福利,本案例中选用DeepSeek-R1,则在此处点DeepSeek-R1 轻量体验包(¥7.00)。若其他案例中选用DeepSeek-V3 则购买ModelArts Studio DeepSeek-V3 轻量体验包(¥3.50)。开通商用模型服务,最后获取API地址、API Key的参数值。3.从 GitCode 拉取源码源码基于 RouYi-Vue 改造,新增了 MCP-Server 并集成了 MCP-Client,实现了 AIChat 可调用 MCP 来操控页面,是 AI 时代前端智能化的一次探索尝试。在 VSCode 新建终端:输入命令拉取代码:git clone https://gitcode.com/huqi-dev/RuoYi-Vue3 三、前端智能化改造1. OpenTiny 助力 MCP-Server 开发@OpenTiny/tiny-agent 基于MCP协议使AI理解与操作用户界面,完成用户任务。它的特性包括但不限于:支持MCP协议 支持MCP客户端 + FunctionCall/ReAct模式的大模型任务调度指令 支持模拟人机交互,让AI操作用户界面,可人为干预可扩展操作哭 丰富的人机交互模拟,支持组件模块API专有扩展开发工具套件 轻松标记编排,生成AI能理解的网站使用说明书首先我们需要配置一下环境,主要是把 MaaS 提供的 DeepSeek R1 接入进来,为我们的前端智能化改造提供核动力。复制 mcp-server/.env-example 内容到 mcp-server/.env 中,填写自己的api key、api url 等。如:url=https://api.modelarts-maas.com/v1/chat/completions apiKey= 此处请替换为您的 api key model=DeepSeek-R1 systemPrompt=You are a helpful assistant with access to tools. 接着在命令行中执行命令,安装依赖并启动项目:cd RuoYi-Vue3/mcp-server/ npm install npm run dev这时候会监听到 3001 端口已经有服务在运行了。我们通过浏览器访问 http://localhost:3001/mcp 能够看到服务正常运行:2. OpenTiny 助力 MCP-Client 开发@OpenTiny/tiny-agent 同样也适用于 MCP-Client 的开发,我们在源码目录的 /workspace/RuoYi-Vue3/src/components/AIChat 下实现了 AIChat 组件和它能调用的 MCP tools。继续新建终端,执行命令安装依赖并运行前端:cd RuoYi-Vue3/ npm install npm run dev此时浏览器会自动打开 rouyi 的前端页面:登录完成之后,我们去到 系统管理-日志管理-操作日志 ,可以看到右下角多了一 AIChat 的入口:我们点击 AIChat 的图标可以打开一个对话框:接着点击 列出目前系统中可用的工具 ,AIChat 会调用 MCP-Server 获取我们定义在客户端的 MCP tools:接着我们再测试一下清空筛选条件功能:刷新页面在搜索条件中随意输入,接着点击 界面操作:见证奇迹的时候到了:原先有值的筛选条件被一一清空了,我们从对话中也能看到 MCP tools 被调用了:3. 代码浅析mcp-server 的代码是参考 tiny-agent/demo-server : cid:link_7tree/main/demo-server 实现:demo-server/.env.example — 示例环境变量,说明必须的配置项package.json — 依赖与运行/构建脚本tsconfig.json — TypeScript 编译配置(生产)tsconfig.dev.json — 开发用的 TypeScript 配置覆盖src/index.ts — 应用入口,配置加载与模块初始化proxy-server.ts — HTTP / WebSocket 代理与路由层(主服务)chat.ts — 聊天 / 会话逻辑(业务处理、上游适配)connector.ts — 上游连接适配器(HTTP/WebSocket 客户端封装)tiny-agent/demo‑server 是一个演示(demo)服务器模块,用于快速搭建后端服务,以便前端或其它客户端能够通过 Web 接口调用 tiny‑agent 的能力。通过它,我们可以看到一个完整的“Agent 服务端”如何接收请求、调用 Agent 模型、返回结果。整体流程为:客户端发送请求,服务端执行 Agent 推理,可能调用工具,然后将结果返回给客户端。前端AIChat 的实现代码主要都在 src/components/AIChat ,包含了 UI 层和 mcp tools 相关的实现,核心代码为:import { EndpointTransport, WebSocketClientEndpoint } from '@opentiny/tiny-agent-mcp-connector'; import { McpValidator } from '@opentiny/tiny-agent-mcp-service'; import { setupMcpService } from '@opentiny/tiny-agent-mcp-service-vue'; import { McpToolParser } from '@opentiny/tiny-agent-task-mcp'; import { useTaskScheduler } from './scheduler'; import mcpToolJson from './mcp-tool.json'; import mcpToolRegistry from '@/utils/mcpToolRegistry'; export function initMcp() { // Connector const wsEndpoint = new WebSocketClientEndpoint({ url: import.meta.env.VITE_CONNECTOR_ENDPOINT_URL }); const endpointTransport = new EndpointTransport(wsEndpoint); // MCP Service const mcpService = setupMcpService(); mcpService.mcpServer.connect(endpointTransport); // MCP Validatorß const mcpValidator = new McpValidator(); mcpService.setValidator(mcpValidator); // Task Scheduler const { taskScheduler, actionManager } = useTaskScheduler(); const doTask = async (task, opt) => taskScheduler.pushTask(task, opt); // MCP Tool Parser & mcp-tool.json const mcpToolParser = new McpToolParser(doTask); mcpToolParser.extractAllTools(mcpToolJson).forEach((tool) => { mcpService.mcpServer.registerTool(tool.name, tool.config, tool.cb); }); // 设置全局MCP工具注册管理器 mcpToolRegistry.setMcpService(mcpService); console.log('[MCP] MCP服务初始化完成,工具注册管理器已设置'); return { wsEndpoint, endpointTransport, mcpService, mcpValidator, taskScheduler, actionManager, mcpToolParser, }; } 实例化:import { initMcp } from './mcp'; const { endpointTransport, mcpValidator } = initMcp(); 完整代码请参考: https://gitcode.com/huqi-dev/RuoYi-Vue3至此,我们完成了基于华为开发者空间云开发环境(容器)探索前端智能化,后续待 OpenTiny 开源 WebAgent 实现,我们再分享基于 OpenTiny Next 的企业智能前端解决方案,我们相信以生成式 UI 和 WebMCP 两大自主核心技术为基础的OpenTiny Next ,势必能加速企业应用的智能化改造。我正在参加【案例共创】第8期 【案例共创】基于华为开发者空间云开发环境(容器)开发构建AI应用 https://bbs.huaweicloud.com/forum/thread-0282197603883890106-1-1.html
-
一、搜索前端技术需求Nuxt.js 是 Vue.js 生态下专注解决 SEO 问题的服务端渲染(SSR)框架,专为需搜索引擎优化的前端场景设计,可兼顾 Vue 开发体验与服务端渲染优势。其核心价值在于破解 Vue 客户端渲染的 SEO 短板 —— 客户端渲染中搜索引擎爬虫难以解析 JS 生成的内容,而 Nuxt.js 部署于 Node.js,接收请求后先从服务端获取数据,完成 HTML 渲染再响应给浏览器,生成的完整 DOM 能被爬虫高效抓取。1.1 需求描述采用vue.js开发搜索界面则SEO不友好,需要解决SEO的问题 1.2 了解SEOSEO,也就是搜索引擎优化的逻辑,其实是非常简单的。这就像是在大学里的学生会主席,你要让投票者给你更多的选票。那么,你需要先「自我优化」,无论是外表还是能力;此外,你还需获得更多意见领袖的推荐,才可以让更多普通选民支持你。同样的,你要让搜索引擎在无数的文章,把你的文章排到前面。你首先需要先做:1. 内部优化:也就是提高文章本身的质量2. 外部优化:也就是让你的文章曝光在更多权威网站上总结:seo是网站为了提高自已的网站排名,获得更多的流量,对网站的结构及内容进行调整优化,以便搜索引擎 (百度,google等)更好抓取到更优质的网站的内容。下图是搜索引擎爬取网站页面的大概流程图:(搜索引擎的工作流程很复杂,下图只是简单概括) 从上图可以看到SEO是网站自己为了方便spider抓取网页而作出的网页内容优化,常见的SEO方法比如:对url链接的规范化,多用restful风格的url,多用静态资源url;注意title、keywords的设置。由于spider对javascript支持不好,对于网页跳转用href标签。 。。。 1.3 服务端渲染和客户端渲染采用什么技术有利于SEO?要解答这个问题需要理解服务端渲染和客户端渲染。什么是服务端渲染?我们用传统的servlet开发来举例:浏览器请求servlet,servlet在服务端生成html响应给浏览器,浏览器展示html的内容,这个过程就是服务端渲染,如下图: 服务端渲染的特点:在服务端生成 html 网页的dom元素。客户端(浏览器)只负责显示dom元素内容。当初随着web2.0的到来,AJAX技术兴起,出现了客户端渲染:客户端(浏览器) 使用AJAX向服务端发起http请 求,获取到了想要的数据,客户端拿着数据开始渲染html网页,生成Dom元素,并最终将网页内容展示给用户, 如下图: 客户端渲染的特点:在服务端只是给客户端响应的了数据,而不是html网页客户端(浏览器)负责获取服务端的数据生成Dom元素。两种方式各有什么优缺点?客户端渲染:缺点 不利于网站进行SEO,因为网站大量使用javascript技术,不利于spider抓取网页。优点 客户端负责渲染,用户体验性好,服务端只提供数据不用关心用户界面的内容,有利于提高服务端的开发效率。适用场景 对SEO没有要求的系统,比如后台管理类的系统,如电商后台管理,用户管理等。 服务端渲染:优点有利于SEO,网站通过href的url将spider直接引到服务端,服务端提供优质的网页内容给spider。缺点服务端完成一部分客户端的工作,通常完成一个需求需要修改客户端和服务端的代码,开发效率低,不利于系统的稳定性。适用场景 对SEO有要求的系统,比如:门户首页、商品详情页面等二、 Nuxt.js介绍2.1 Nuxt.js介绍移动互联网的兴起促进了web前后端分离开发模式的发展,服务端只专注业务,前端只专注用户体验,前端大量运 用的前端渲染技术,比如流行的vue.js、react框架都实现了功能强大的前端渲染。但是,对于有SEO需求的网页如果使用前端渲染技术去开发就不利于SEO了,有没有一种即使用vue.js、react的前 端技术也实现服务端渲染的技术呢?其实,对于服务端渲染的需求,vue.js、react这样流行的前端框架提供了服务 端渲染的解决方案。 从上图可以看到: react框架提供next.js实现服务端渲染。 vue.js框架提供Nuxt.js实现服务端渲染2.2 Nuxt.js工作原理下图展示了从客户端请求到Nuxt.js进行服务端渲染的整体的工作流程 用户打开浏览器,输入网址请求到Node.js部署在Node.js的应用Nuxt.js接收浏览器请求,并请求服务端获取数据Nuxt.js获取到数据后进行服务端渲染Nuxt.js将html网页响应给浏览器Nuxt.js使用了哪些技术?Nuxt.js使用Vue.js+webpack+Babel三大技术框架/组件,如下图: Babel 是一个js的转码器,负责将ES6的代码转成浏览器识别的ES5代码。 Webpack是一个前端工程打包工具。 Vue.js是一个优秀的前端框架。Nuxt.js的特性有哪些?基于 Vue.js自动代码分层服务端渲染强大的路由功能,支持异步数据静态文件服务ES6/ES7 语法支持打包和压缩 JS 和 CSSHTML头部标签管理本地开发支持热加载集成ESLint支持各种样式预处理器: SASS、LESS、 Stylus等等总结Nuxt.js 是 Vue.js 生态下专注解决 SEO 问题的服务端渲染(SSR)框架,专为需搜索引擎优化的前端场景设计,可兼顾 Vue 开发体验与服务端渲染优势。其核心价值在于破解 Vue 客户端渲染的 SEO 短板 —— 客户端渲染中搜索引擎爬虫难以解析 JS 生成的内容,而 Nuxt.js 部署于 Node.js,接收请求后先从服务端获取数据,完成 HTML 渲染再响应给浏览器,生成的完整 DOM 能被爬虫高效抓取。架构上以 “约定优于配置” 为核心,基于 Vue.js、Webpack、Babel 构建,具备自动路由生成、代码分层等特性,无需手动配置路由,支持异步数据加载与 HTML 头部标签管理。同时内置 SEO 优化能力,可自动生成 meta 标签、XML 站点地图,规范 URL 处理,比手动配置更高效。适用场景聚焦内容密集型网站(如博客、商品详情页)及 SEO 关键项目,能平衡开发效率与性能,既保留前端开发灵活性,又通过服务端渲染提升页面收录与排名表现。
-
webpack入门使用vue.js开发大型应用需要使用webpack打包工具,本节研究webpack的使用方法。1.3.1 webpack介绍 Webpack 是一个前端资源的打包工具,它可以将js、image、css等资源当成一个模块进行打包。从图中我们可以看出,Webpack 可以将js、css、png等多种静态资源 进行打包,使用webpack有什么好处呢?1 、模块化开发程序员在开发时可以分模块创建不同的js、 css等小文件方便开发,最后使用webpack将这些小文件打包成一个文件,减少了http的请求次数。webpack可以实现按需打包,为了避免出现打包文件过大可以打包成多个文件。2 、 编译typescript、ES6等高级js语法随着前端技术的强大,开发中可以使用javascript的很多高级版本,比如:typescript、ES6等,方便开发, webpack可以将打包文件转换成浏览器可识别的js语法。3 、CSS预编译webpack允许在开发中使用Sass 和 Less等原生CSS的扩展技术,通过sass-loader、less-loader将Sass 和 Less的 语法编译成浏览器可识别的css语法。webpack的缺点:1 、配置有些繁琐2 、文档不丰富1.3.2 安装webpack1.3.2.1 安装Node.jswebpack基于node.js运行,首先需要安装node.js。 为什么会有node.js?传统意义上的 JavaScript 运行在浏览器上,Chrome 使用的 JavaScript 引擎是 V8,Node.js 是一个运行在服务端的框架,它的底层就使用了 V8 引擎,这样就可以使用javascript去编写一些服务端的程序,这样也就实现了用javaScript去开发 Apache + PHP 以及 Java Servlet所开发的服务端功能,这样做的好处就是前端和后端都采用javascript,即开发一份js程序即可以运行在前端也可以运行的服务端,这样比一个应用使用多种语言在开发效率上要高,不过node.js属于新兴产品,一些公司也在尝试使用node.js完成一些业务领域,node.js基于V 8 引擎,基于事件驱动机制,在特定领域性能出色,比如用node.js实现消息推送、状态监控等的业务功能非常合适。下边我们去安装Node.js:1 、下载对应你系统的Node.js版本:https://nodejs.org/en/download/ 推荐下载LTS版本,本教程安装 9 .4.0。2 、选安装目录进行安装默认即可安装完成检查PATH环境变量是否设置了node.js的路径。3 、测试在命令提示符下输入命令node ‐v会显示当前node的版本1 .3.2.2 安装NPM1 、自动安装NPMnpm全称Node Package Manager,他是node包管理和分发的工具,使用NPM可以对应用的依赖进行管理,NPM的功能和服务端项目构建工具maven差不多,我们通过npm 可以很方便地下载js库,打包js文件。node.js已经集成了npm工具,在命令提示符输入 npm -v 可查看当前npm版本 2 、设置包路径包路径就是npm从远程下载的js包所存放的路径。使用 npm config ls 查询NPM管理包路径(NPM下载的依赖包所存放的路径) NPM默认的管理包路径在C:/用户/[用户名]/AppData/Roming/npm/node_meodules,为了方便对依赖包管理,我 们将管理包的路径设置在单独的地方,本教程将安装目录设置在node.js的目录下,创建npm_modules和 npm_cache,执行下边的命令:本教程安装node.js在D:\Program Files\nodejs下所以执行命令如下:npm config set prefix "C:\Program Files\nodejs\npm_modules"npm config set prefix "D:\nodejs\npm_modules" (更改本地仓库的位置)npm config set cache "c:\Program Files\nodejs\npm_cache"npm config set cache "D:\nodejs\npm_cache" (更改本地仓库的缓存位置)此时再使用 npm config ls 查询NPM管理包路径发现路径已更改 npm config set registry http://registry.npm.taobao.org 配置到此为止结束。3 、安装cnpmnpm默认会去国外的镜像去下载js包,在开发中通常我们使用国内镜像,这里我们使用淘宝镜像下边我们来安装cnpm:有时我们使用npm下载资源会很慢,所以我们可以安装一个cnmp(淘宝镜像)来加快下载速度。输入命令,进行全局安装淘宝镜像。npm install -g cnpm --registry=http://registry.npm.taobao.org安装后,我们可以使用以下命令来查看cnpm的版本cnpm -v nrm ls 查看镜像已经指向taobao 使nrm use XXX切换 镜像如果nrm没有安装则需要进行全局安装:cnpm install -g nrm4 、非连网环境安装cnpm从本小节第 3 步开始就需要连网下载npm包,如果你的环境不能连网在老师的资料文件下有已经下载好的webpack相关包,下边是安装方法。1 )配置环境变量NODE_HOME = D:\Program Files\nodejs (node.js安装目录)在PATH变量中添加:%NODE_HOME%;%NODE_HOME%\npm_modules;2 )找到npm包路径根据上边的安装说明npm包路径被设置到了node.js安装目录下的npm_modules目录。可以使用npm config ls查看。拷贝课程资料中的 npm_modules.zip到node.js安装目录,并解压npm_modules.zip覆盖本目录下的 npm_modules文件夹。3 )完成上边步骤测试cnpm -v1.3.2.3 安装webpack1 、连网安装webpack安装分为本地安装和全局安装:本地安装:仅将webpack安装在当前项目的node_modules目录中,仅对当前项目有效。全局安装:将webpack安装在本机,对所有项目有效,全局安装会锁定一个webpack版本,该版本可能不适用某个项目。全局安装需要添加 -g 参数。进入webpacktest测试目录目录,运行:1 )本地安装:只在我的项目中使用webpack,需要进行本地安装,因为项目和项目所用的webpack的版本不一样。本地安装就会将webpack的js包下载到项目下的npm_modeuls目录下。在门户目录下创建webpack测试目录webpacktest01:npm install --save-dev webpack 或 cnpm install --save-dev webpacknpm install --save-dev webpack-cli (4.0以后的版本需要安装webpack-cli)2 )全局安装加-g,如下:全局安装就将webpack的js包下载到npm的包路径下。npm install webpack -g 或 cnpm install webpack -g3 )安装webpack指定的版本:本教程使用webpack3.6.0,安装webpack3.6.0:进入webpacktest测试目录,运行:cnpm install --save-dev webpack@3.6.全局安装:npm install webpack@3.6.0 -g或 cnpm install webpack@3.6.0 -g2 、非连网安装参考上边 “非连网环境安装cnpm”描述,将课程资料中的 npm_modules.zip到node.js安装目录,并解压 npm_modules.zip覆盖本目录下的npm_modules文件夹。说明:已执行 “非连网环境安装cnpm”下的操作不用重复执行。测试:在cmd状态输入webpack,出现如下提示说明 webpack安装成功 总结Webpack 是基于 Node.js 的现代前端静态模块打包器,核心功能是将 JS、CSS、图片等多种资源视作模块,通过打包优化项目结构与性能,是 Vue 等框架开发大型应用的核心工具。其核心优势显著:支持模块化开发,可将代码拆分为小模块便于维护,打包后减少 HTTP 请求次数,还能按需拆分避免文件过大;通过 loader 机制编译 ES6、TypeScript 等高级语法及 Sass、Less 等 CSS 预编译语言,适配浏览器兼容;搭配插件生态可实现热模块替换等功能,提升开发效率。安装需先部署 Node.js(含 npm 包管理工具),可配置淘宝镜像(cnpm)加速下载,支持全局与本地两种安装方式,本地安装更适配多项目版本差异。虽存在配置繁琐、早期文档不足的缺点,但凭借强大的资源处理与优化能力,仍是前端工程化开发的主流工具。
-
一.webpack和vite的区别1.构建速度不同Webpack: Webpack的构建速度相对较慢,尤其在大型项目中,因为它需要分析整个依赖图,进行多次文件扫描和转译。Vite: Vite以开发模式下的极速构建著称。它利用ES模块的特性,只有在真正需要时才编译文,而不是整个项目。这使得它在开发环境下几乎是即时的。2.开发模式不同Webpack: Webpack通常使用热模块替换(HMR)来实现快速开发模式,但配置相对复杂。Vite: 采用了基于ES Module的开发服务器,只有在需要时才会编译对应的模块,大幅度提升了开发环境的响应速度。3.配置复杂度不同Webpack: Webpack的配置相对复杂,特别是在处理不同类型的资源和加载器时。Vite: Vite在设计上更注重开箱即用,大部分场景下用户无需自己写配置文件,但同时也支持自定义配置,使其适用于复杂项目。4.插件生态不同Webpack: Webpack拥有庞大的插件生态系统,适用于各种不同的需求。Vite: Vite也有相当数量的插件,但相对较小,因为它的开发模式和构建方式减少了对一些传统插件的需求。5.编译方式不同Webpack: webpack在编译过程中,会将所有模块打包为一个bundle.js文件,然后再运行这个文件。Vite: 没有打包的步骤,它利用了浏览器的ES Module Imports特性,只有在真正需要时才编译文件。6.应用场景不同Webpack: 适用于复杂的大型项目,特别是需要大量自定义配置和复杂构建管道的项目。Vite: 更适用于小到中型项目,或者需要快速开发原型和小型应用的场景。二.为什么vite启动速度比webpack快?1、开发模式的差异12345在开发环境中,Webpack 是先打包再启动开发服务器,而 Vite 则是直接启动,然后再按需编译依赖文件。(大家可以启动项目后检查源码 Sources 那里看到) 这意味着,当使用 Webpack 时,所有的模块都需要在开发前进行打包,这会增加启动时间和构建时间。 而 Vite 则采用了不同的策略,它会在请求模块时再进行实时编译,这种按需动态编译的模式极大地缩短了编译时间,特别是在大型项目中,文件数量众多,Vite 的优势更为明显。Webpack启动Vite启动2、对ES Modules的支持现代浏览器本身就支持 ES Modules,会主动发起请求去获取所需文件。Vite充分利用了这一点,将开发环境下的模块文件直接作为浏览器要执行的文件,而不是像 Webpack 那样先打包,再交给浏览器执行。这种方式减少了中间环节,提高了效率。什么是ES Modules?通过使用 export 和 import 语句,ES Modules 允许在浏览器端导入和导出模块。当使用 ES Modules 进行开发时,开发者实际上是在构建一个依赖关系图,不同依赖项之间通过导入语句进行关联。主流浏览器(除IE外)均支持ES Modules,并且可以通过在 script 标签中设置 type="module"来加载模块。默认情况下,模块会延迟加载,执行时机在文档解析之后,触发DOMContentLoaded事件前。3、底层语言的差异Webpack 是基于 Node.js 构建的,而 Vite 则是基于 esbuild 进行预构建依赖。esbuild 是采用 Go 语言编写的,Go 语言是纳秒级别的,而 Node.js 是毫秒级别的。因此,Vite 在打包速度上相比Webpack 有 10-100 倍的提升。什么是预构建依赖?预构建依赖通常指的是在项目启动或构建之前,对项目中所需的依赖项进行预先的处理或构建。这样做的好处在于,当项目实际运行时,可以直接使用这些已经预构建好的依赖,而无需再进行实时的编译或构建,从而提高了应用程序的运行速度和效率。4、热更新的处理在 Webpack 中,当一个模块或其依赖的模块内容改变时,需要重新编译这些模块。而在 Vite 中,当某个模块内容改变时,只需要让浏览器重新请求该模块即可,这大大减少了热更新的时间。总结总的来说,Vite 之所以比 Webpack 快,主要是因为它采用了不同的开发模式、充分利用了现代浏览器的 ES Modules 支持、使用了更高效的底层语言,并优化了热更新的处理。这些特点使得 Vite在大型项目中具有显著的优势,能够快速启动和构建,提高开发效率。
-
vxe-table 如何在单元格内容渲染成可点击复制的文本通过 cellRender.name='VxeText',设置参数 clickToCopy=true 就可以开启文本复制功能,点击复制回会自动将文本复制到剪贴板<template> <div> <vxe-grid v-bind="gridOptions"></vxe-grid> </div> </template> <script setup> import { reactive } from 'vue' const roleCellRender = reactive({ name: 'VxeText', props: { clickToCopy: true } }) const addressCellRender = reactive({ name: 'VxeText', props: { clickToCopy: true, status: 'error' } }) const gridOptions = reactive({ border: true, showOverflow: true, columns: [ { type: 'seq', width: 70 }, { field: 'name', title: 'Name', minWidth: 200 }, { field: 'role', title: 'Role', width: 120, cellRender: roleCellRender }, { field: 'address', title: 'Address', width: 300, cellRender: addressCellRender } ], data: [ { id: 10001, name: 'Test1', role: 'Develop', sex: 'Man', age: 28, address: 'test abc' }, { id: 10002, name: 'Test2', role: 'Test', sex: 'Women', age: 22, address: 'Guangzhou' }, { id: 10003, name: 'Test3', role: 'PM', sex: 'Man', age: 32, address: 'Shanghai' }, { id: 10004, name: 'Test4', role: 'Designer', sex: 'Women', age: 24, address: 'Shanghai' } ] }) </script>
-
vxe-tree-select 树形下拉框当使用懒加载数据时如何回显当使用懒加载或者当某个选项被删除时,显示自定义回显;比如使用懒加载树列表,由于数据未被加载,这时候已选的数据就不能被回显,导致显示了 value值,而不是 label。还有一种场景就是组织架构人员选择,当选择某个人员后,可能人员变动离职,数据被删掉了,这个时候也无法回显。那么怎么解决以上几种情况,解决方式也很简单官网:https://vxeui.comgithub:https://github.com/x-extends/vxe-pc-uigitee:https://gitee.com/x-extends/vxe-pc-ui问题无法显示对应的label解决效果比如以下懒加载树选择,所有的子项都没有点击加载,也可以正确回显label代码可以通过设置 lazy-options 来将指定节点放入用来回显,将不存在选项的数据额外放到这里,就可以实现自动回显<template> <div> <vxe-tree-select v-model="val1" :options="treeList" :lazy-options="lazyList" :treeConfig="treeConfig" multiple clearable></vxe-tree-select> </div> </template> <script setup> import { ref, reactive } from 'vue' const val1 = ref(['4-2']) const treeConfig = reactive({ lazy: true, loadMethod ({ node }) { return getNodeListApi(node) } }) const treeList = ref([ { label: '节点2', value: '2', hasChild: true }, { label: '节点3', value: '3', hasChild: true }, { label: '节点4', value: '4', hasChild: true }, { label: '节点5', value: '5', hasChild: false } ]) const lazyList = ref([ { label: '节点4-2', value: '4-2' } ]) let treeKey = 1 const getNodeListApi = (node) => { return new Promise(resolve => { // 模拟后端接口 setTimeout(() => { resolve([ { label: `节点${node.value}-${treeKey}`, value: `节点${node.value}-${treeKey}`, hasChild: Math.random() * 10 < 6 }, { label: `节点${node.value}-${treeKey + 1}`, value: `节点${node.value}-${treeKey + 1}`, hasChild: Math.random() * 10 < 6 } ]) treeKey += 2 }, 500) }) } </script>
-
一、Vue.js 简介Vue.js 是一套用于构建用户界面的渐进式框架,由尤雨溪创建。与其他大型框架不同,Vue 被设计为可以自底向上逐层应用,核心库只关注视图层,易于上手,也便于与第三方库或既有项目整合。Vue 的核心特性:响应式数据绑定:自动追踪依赖,更新DOM组件系统:可复用、可组合的UI组件虚拟DOM:高效的DOM更新策略丰富的生态系统:Vue Router、Vuex、Vue CLI等工具支持二、快速开始1. 安装方式CDN引入(适合快速原型开发):html <script src="https://cdn.jsdelivr.net/npm/vue@3.2.31/dist/vue.global.js"></script>使用Vue CLI(推荐生产环境使用):bash npm install -g @vue/clivue create my-projectcd my-projectnpm run serve2. 基础示例html <div id="app"> <h1>{{ message }}</h1> <button @click="reverseMessage">反转消息</button></div><script>const { createApp } = VuecreateApp({ data() { return { message: 'Hello Vue!' } }, methods: { reverseMessage() { this.message = this.message.split('').reverse().join('') } }}).mount('#app')</script>三、核心概念详解1. 模板语法Vue 使用基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层组件实例的数据。html <div id="bind-attribute"> <span v-bind:title="message">悬停查看动态绑定的提示信息!</span> <!-- 缩写 --> <span :title="message">简写形式</span></div>2. 计算属性和侦听器计算属性:js computed: { reversedMessage() { return this.message.split('').reverse().join('') }}侦听器:js watch: { message(newVal, oldVal) { console.log(`消息从"${oldVal}"变为"${newVal}"`) }}3. 条件渲染和列表渲染v-if:html <p v-if="seen">现在你看到我了</p><p v-else>你看不到我了</p>v-for:html <ul> <li v-for="(item, index) in items" :key="item.id"> {{ index }} - {{ item.text }} </li></ul>4. 组件系统组件定义:js // 定义一个名为 button-counter 的新组件app.component('button-counter', { data() { return { count: 0 } }, template: ` <button @click="count++"> 点了 {{ count }} 次! </button> `})组件使用:html <div id="components-demo"> <button-counter></button-counter></div>四、Vue 3 新特性1. Composition APIjs import { ref, computed, onMounted } from 'vue'export default { setup() { const count = ref(0) const double = computed(() => count.value * 2) function increment() { count.value++ } onMounted(() => { console.log('组件已挂载') }) return { count, double, increment } }}2. Teleport 传送门html <teleport to="body"> <div class="modal" v-if="showModal"> 我是一个模态框! </div></teleport>3. 片段(Fragments)html <template> <header>...</header> <main>...</main> <footer>...</footer></template>五、生态系统1. Vue Routerjs import { createRouter, createWebHistory } from 'vue-router'const routes = [ { path: '/', component: Home }, { path: '/about', component: About }]const router = createRouter({ history: createWebHistory(), routes})2. Vuex/Pinia 状态管理Vuex示例:js const store = createStore({ state() { return { count: 0 } }, mutations: { increment(state) { state.count++ } }})3. Vue CLI 和 Vite使用Vite创建项目:bash npm init vite@latest my-vue-app --template vuecd my-vue-appnpm installnpm run dev六、最佳实践组件设计原则:单一职责原则合理的props/emit设计可复用性考虑性能优化:合理使用v-if和v-show列表渲染使用key组件懒加载代码组织:按功能而非类型组织代码使用Composition API提取可复用逻辑统一代码风格Vue.js 以其简洁的API设计、灵活的组件系统和活跃的社区,已成为现代Web开发的主流选择之一。无论是小型项目还是大型企业应用,Vue都能提供高效的开发体验和出色的性能表现。
上滑加载中
推荐直播
-
华为云码道 × 仓颉编程:工程化AI编码探索2026/05/27 周三 19:00-21:00
刘俊杰-华为云仓颉语言专家/李炎-华为云码道技术专家/王智鹏-OpenCangjie开源社区发起人
本场直播围绕华为云仓颉语言与华为云码道的深度结合,展示华为云智能编程从零基础到高效落地的完整生态能力。以华为云码道为引擎,仓颉语言为载体,带给大家日常提效、趣味创新到极速量产的开发体验。
即将直播
热门标签