营销公司网站模板下载,wordpress开cdn好吗,域名注册商,遂宁移动网站建设#x1f31f; 前言 欢迎来到我的技术小宇宙#xff01;#x1f30c; 这里不仅是我记录技术点滴的后花园#xff0c;也是我分享学习心得和项目经验的乐园。#x1f4da; 无论你是技术小白还是资深大牛#xff0c;这里总有一些内容能触动你的好奇心。#x1f50d; #x… 前言 欢迎来到我的技术小宇宙 这里不仅是我记录技术点滴的后花园也是我分享学习心得和项目经验的乐园。 无论你是技术小白还是资深大牛这里总有一些内容能触动你的好奇心。 洛可可白个人主页 个人专栏✅前端技术 ✅后端技术 个人博客洛可可白博客 代码获取bestwishes0203 封面壁纸洛可可白wallpaper 文章目录 广州5k前端面试题惊呆我内容太肝谨慎入内1. 浏览器渲染原理2. https如何进行加密3. spa首屏加载慢优化4. vue双向绑定原理5. vuex设计与实现6. vue-router底层原理7. mvvm设计与实现设计原理实现方式示例实现 8. async,await底层实现9. promise底层实现11. computea和watch的区别和应用场景computed计算属性watch侦听属性**应用场景**总结 12. js垃圾回收机制工作原理 13. 前端缓存机制浏览器缓存Service WorkersLocal Storage 和 Session StorageIndexedDB应用缓存Application Cache缓存策略 往期精彩回顾 广州5k前端面试题惊呆我内容太肝谨慎入内
1. 浏览器渲染原理
浏览器渲染原理涉及将网页代码转换成用户可视界面的过程。以下是浏览器渲染页面的基本步骤 加载浏览器发起HTTP请求从服务器获取HTML文档。 解析浏览器解析HTML文档创建DOM文档对象模型树。DOM树是由HTML元素构成的节点层次结构。 构建CSSOM浏览器解析CSS文件和内联样式构建CSSOMCSS对象模型树。CSSOM树包含了页面的样式信息。 合并DOM与CSSOM浏览器将DOM树和CSSOM树合并形成渲染树render tree。渲染树包含了所有需要显示在屏幕上的元素信息包括样式属性。 布局浏览器对渲染树进行布局计算确定每个元素的位置和大小这一过程也称为“重排”reflow。 绘制浏览器将布局后的信息转换成像素这个过程称为“重绘”repaint。随后浏览器将像素数据发送到显卡由显卡输出到显示器上。 合成在某些情况下浏览器会使用硬件加速来合成多个图层这可以提高渲染效率。
在整个渲染过程中浏览器可能会执行优化措施如缓存、异步加载等以提升页面加载和交互性能。了解这些原理对于前端开发者来说非常重要它有助于诊断性能问题、优化页面加载速度和改善用户体验。
2. https如何进行加密
HTTPS超文本传输安全协议是一种安全的网络传输协议它在HTTP的基础上通过SSL/TLS协议提供了数据加密、完整性验证和身份认证的功能。HTTPS的加密过程主要包括以下步骤 握手阶段 客户端向服务器发起HTTPS请求。服务器响应并发送其SSL证书该证书包含了服务器的公钥和由证书颁发机构CA签发的信息。客户端验证服务器证书的有效性包括证书是否过期、是否由可信CA签发等。验证通过后客户端会生成一个随机数称为预主密钥并使用服务器的公钥加密后发送给服务器。 密钥交换 服务器使用自己的私钥解密收到的预主密钥。客户端和服务器现在都有了相同的预主密钥将使用它来生成一组对称加密的密钥会话密钥用于后续的数据加密通信。 加密通信 使用生成的会话密钥客户端和服务器之间的所有数据传输都将被加密。即使数据在传输过程中被拦截攻击者也无法解密和读取数据内容因为他们没有会话密钥。 会话结束 一旦通信结束会话密钥将被丢弃确保每次会话都使用新的密钥增加了安全性。
HTTPS的加密机制确保了数据传输的安全性尤其适用于涉及敏感信息如登录凭据、个人信息、支付信息等的场合。通过这种方式HTTPS提供了一种可靠的保护措施防止数据在传输过程中被窃听或篡改。
3. spa首屏加载慢优化
SPA单页应用首屏加载慢是常见的性能问题主要原因是JavaScript文件和依赖的加载、解析、执行过程可能导致渲染阻塞。以下是一些优化SPA首屏加载速度的策略 代码分割使用Webpack等打包工具进行代码分割将代码拆分为多个块chunk按需加载减少首屏加载时的JavaScript体积。 异步加载将非关键的JavaScript和CSS资源设置为异步加载例如使用async或defer属性确保首屏渲染不受阻塞。 懒加载实现图片和组件的懒加载只有当用户滚动到页面的相应位置时才加载资源。 优化资源加载使用HTTP/2减少连接数启用Gzip或Brotli压缩资源减少传输数据大小。 预加载关键资源通过link relpreload预加载关键CSS文件和字体确保它们在渲染前已加载完毕。 服务端渲染SSR使用服务端渲染生成首屏HTML减少客户端渲染时间。 缓存策略利用浏览器缓存对静态资源设置合理的缓存策略减少重复加载。 优化DOM操作减少首屏渲染所需的DOM操作避免复杂的DOM树结构。 使用CDN将静态资源部署到CDN上减少资源加载时间。 性能监控使用性能监控工具如Lighthouse、WebPageTest定期检查网站性能找出瓶颈并进行优化。
通过这些策略的组合使用可以显著提升SPA的首屏加载速度改善用户体验。开发者应根据具体情况选择合适的优化方法并持续监测优化效果。
4. vue双向绑定原理
Vue.js 的双向绑定是其核心特性之一它允许开发者在表单输入和应用状态之间建立一个双向连接。Vue 实现双向绑定的原理主要依赖于响应式系统该系统结合了观察者模式、依赖收集和发布订阅模式。以下是 Vue 双向绑定的基本原理 数据劫持 Vue 使用 Object.defineProperty 方法对数据对象的属性进行劫持将每个属性转换为 getter 和 setter。这样每当属性被访问getter 被调用或属性值被修改setter 被调用时Vue 都能够知道。 依赖收集 当渲染函数或计算属性被执行时它们会访问响应式数据的属性触发这些属性的 getter。在 getter 中Vue 会记录当前正在执行的渲染函数或计算属性作为依赖。这个过程称为依赖收集确保 Vue 知道哪些组件需要在数据变化时重新渲染。 观察者模式 Vue 的响应式系统是基于观察者模式实现的。每个组件实例都对应一个观察者对象它会在数据变化时收到通知并执行相应的组件更新。 发布订阅 当属性的 setter 被调用时意味着数据发生了变化。Vue 会触发该属性的 setter通知所有依赖于这个属性的观察者即组件进行相应的更新。 指令v-model Vue 提供了 v-model 指令来实现表单输入和应用状态之间的双向绑定。当用户输入时v-model 会更新对应的数据模型反之当数据模型变化时v-model 也会更新 DOM 中的输入框显示。 虚拟DOM Vue 在内部使用虚拟DOM来提高性能。当数据变化时Vue 会生成一个新的虚拟DOM树并与旧的虚拟DOM树进行比较diff。Vue 会找出两棵树之间的差异并计算出最小的更新操作来应用到实际的DOM上从而实现高效的视图更新。
通过这些机制Vue 能够在数据变化时自动更新视图同时在视图变化时如用户输入更新数据实现所谓的双向绑定。这种机制大大简化了数据与视图同步的复杂性使得开发者能够更加专注于应用逻辑。
5. vuex设计与实现
Vuex 是 Vue.js 应用的状态管理模式和库它采用集中式存储管理应用的所有组件的状态并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 的设计遵循了几个核心原则 单一状态树整个应用的状态被存储在一个对象树中称为“state”。这使得状态的预测和管理变得更加简单。 状态管理Vuex 提供了一套严格的规则和约定使得状态的变化可追踪和调试。 数据流的单一方向Vuex 应用的状态变化是可预测的所有的状态变更都显式地通过变更状态的函数进行。
Vuex 的基本实现包括以下几个部分 State存储所有应用级别的状态。 Getters允许你从 state 中派生出一些状态例如过滤列表、计算属性值等。 Mutations更改 Vuex 的 state 的唯一方法是提交 mutation。Mutation 是同步函数其目的是修改 state。 Actions类似于 mutations但可以包含任意异步操作。Action 提交的是 mutation而不是直接变更状态。 Mutations 和 Actions 的区别Mutations 必须是同步函数而 Actions 可以是异步的。Mutations 直接变更状态而 Actions 通过提交 Mutations 来间接变更状态。 Modules当应用变得复杂时状态管理也会变得很复杂。Vuex 允许将 store 分割成模块module。每个模块拥有自己的 state、getters、mutations、actions甚至是嵌套子模块。
在实现 Vuex 时首先需要创建一个 store 实例定义好 state、getters、mutations 和 actions。然后在 Vue 实例中注入 Vuex store通过 this.$store 访问 state 和 getters通过 this.$store.commit 和 this.$store.dispatch 触发状态变更。
例如创建一个简单的 Vuex store
import Vue from vue;
import Vuex from vuex;Vue.use(Vuex);const store new Vuex.Store({state: {count: 0},getters: {doubleCount: state state.count * 2},mutations: {increment(state) {state.count;}},actions: {incrementIfOdd({ state, commit }) {if (state.count % 2 ! 0) {commit(increment);}}}
});export default store;在 Vue 组件中使用
export default {computed: {doubleCount() {return this.$store.getters.doubleCount;}},methods: {increment() {this.$store.commit(increment);},incrementIfOdd() {this.$store.dispatch(incrementIfOdd);}}
};通过这种方式Vuex 提供了一个清晰、结构化的方式来管理应用的状态使得状态变化可预测、可追踪并且易于维护。
6. vue-router底层原理
Vue Router 是 Vue.js 的官方路由管理器它与 Vue.js 核心深度集成使得在单页应用中构建复杂的页面路由变得简单。Vue Router 的底层原理可以从以下几个方面来理解 路由映射 Vue Router 允许开发者定义路由映射即 URL 路径与组件的对应关系。在初始化时Vue Router 会解析路由配置创建一个路由表用于匹配 URL 并找到对应的组件。 路由模式 Vue Router 支持两种路由模式Hash 模式和 History 模式。Hash 模式依赖 URL 的 hash 部分例如 #/而 History 模式利用 HTML5 History API 来实现干净的 URL不需要 hash。 路由导航 用户点击导航链接或使用编程式导航如 this.$router.push时Vue Router 会根据当前 URL 和路由表来决定要渲染哪个组件。如果是 History 模式Vue Router 还会通过 HTML5 History API 来改变 URL而不影响页面的重新加载。 视图渲染 Vue Router 使用一个 router-view 组件作为渲染目标根据当前路由的匹配结果动态地切换组件。同时可以使用 router-link 或 nuxt-link 组件来创建导航链接Vue Router 会自动处理链接的激活状态。 路由守卫 Vue Router 提供了路由守卫Route Guards允许在路由进入或离开时执行逻辑如验证用户权限、记录日志等。守卫可以在全局或局部使用支持异步操作。 嵌套路由 Vue Router 支持嵌套路由允许子组件根据其所在的父路由动态地渲染。这通过路由配置中的 children 属性实现使得应用可以构建多层级的页面结构。 懒加载 Vue Router 支持组件的懒加载即组件直到需要渲染时才加载。这可以减少应用的初始加载时间提升性能。 导航栈 在某些情况下Vue Router 会维护一个导航栈记录用户的操作历史支持前进和后退操作。
Vue Router 的设计使得开发者能够轻松地管理应用的路由同时提供了丰富的功能来满足不同场景下的路由需求。通过上述原理Vue Router 为 Vue.js 应用提供了强大的路由功能使得开发者可以构建出具有复杂路由逻辑的单页应用。
7. mvvm设计与实现
MVVMModel-View-ViewModel是一种软件架构模式广泛应用于现代前端框架中如Vue.js、Angular和Knockout.js等。MVVM 的核心思想是将视图层View和业务逻辑层Model分离通过ViewModel作为中介进行数据绑定和命令传递从而实现视图和模型的自动同步。以下是MVVM设计的基本原理和实现方式
设计原理 模型Model代表应用的数据和业务逻辑通常与后端数据源进行交互。Model 不直接与视图相关联而是通过 ViewModel 间接与视图通信。 视图View展示数据给用户的界面。在MVVM模式中视图只负责展示不包含业务逻辑。视图通过数据绑定与 ViewModel 交互。 视图模型ViewModel连接视图和模型的中介。ViewModel 包含了视图中所有数据的副本以及操作这些数据的命令。ViewModel 通过数据绑定将用户在视图上的操作转换为模型的更改同时将模型的状态更新反映到视图上。
实现方式 数据绑定MVVM模式通常使用数据绑定技术如Vue.js中的双向数据绑定来自动同步视图和 ViewModel 的数据。数据绑定可以是双向的双向绑定或单向的单向数据流。 依赖属性和命令ViewModel中的属性被标记为依赖属性如Vue中的data函数返回的数据当这些属性的值发生变化时视图会自动更新。命令如Vue中的methods则是ViewModel中定义的函数用于处理用户的交互操作。 模板引擎许多MVVM框架提供了模板引擎允许开发者在HTML模板中使用简洁的语法来声明数据绑定和命令。例如在Vue.js中可以使用{{ expression }}进行文本插值使用v-bind进行属性绑定使用v-on或来监听事件。 编译模板框架会在应用初始化时编译模板将模板中的绑定转换为相应的数据监听器和更新函数。当ViewModel中的数据变化时监听器会触发更新函数从而更新视图。 组件化MVVM模式支持将视图和ViewModel进一步分解为可复用的组件。每个组件都有自己的视图模板和ViewModel逻辑这使得应用的开发和维护更加模块化。
示例实现
以Vue.js为例一个简单的MVVM实现可能如下所示
// ViewModel
const vm new Vue({el: #app,data: {message: Hello MVVM!},methods: {reverseMessage() {this.message this.message.split().reverse().join();}}
});!-- View --
div idappp{{ message }}/pbutton clickreverseMessageReverse Message/button
/div在这个例子中message是ViewModel中的数据通过{{ message }}在视图中显示。点击按钮时reverseMessage方法被触发ViewModel中的数据更新视图随之更新。
MVVM模式通过解耦视图和模型简化了前端开发使得业务逻辑和用户界面的变更更加独立和易于管理。
8. async,await底层实现
async 和 await 是 JavaScript 中用于简化异步编程的关键字。它们在 ES2017ES8中被引入基于 Promise 实现提供了一种更加直观和易于理解的方式来处理异步操作。以下是 async 和 await 的底层实现原理 async 关键字 当你在函数声明前使用 async 关键字时该函数隐式返回一个 Promise 对象。async 函数内部返回的任何值都会被包装成一个已解决fulfilled的 Promise。如果 async 函数内部抛出异常该异常会被 Promise 捕获并使得 Promise 变为拒绝rejected状态。 await 关键字 await 只能在 async 函数内部使用它后面通常跟随一个 Promise 对象。当执行到 await 表达式时如果 Promise 已经解决await 表达式的值就是 Promise 解决的值。如果 Promise 还在等待中await 会暂停 async 函数的执行直到 Promise 完成无论是解决还是拒绝。在等待 Promise 期间控制权会返回给执行环境允许其他代码运行例如事件循环可以继续进行。 底层实现 async 和 await 的实现依赖于 Promise 的微任务microtask机制。当遇到 await 表达式时当前的 async 函数会暂停执行并将当前执行上下文包括局部变量等保存在内存中。一旦相关的 Promise 完成之前暂停的 async 函数会恢复执行并且 await 表达式的值会被设置为 Promise 的结果。如果 await 表达式抛出异常异常会被包装成一个新 Promise 并拒绝这个新 Promise 会替换原来的 Promise。 错误处理 使用 try...catch 语句可以捕获 async 函数中由 await 抛出的异常。如果 async 函数内部没有捕获到异常它会冒泡到外部调用者就像普通的 Promise 一样。
以下是一个简单的 async 和 await 示例
async function fetchData() {try {const response await fetch(https://api.example.com/data);const data await response.json();return data;} catch (error) {console.error(Error fetching data:, error);}
}fetchData().then(data {console.log(Fetched data:, data);
});在这个例子中fetchData 函数使用 async 关键字声明内部使用 await 等待网络请求完成。如果请求成功它会解析响应并返回数据。如果请求失败它会捕获异常并记录错误。
async 和 await 的引入使得异步代码的编写和阅读更加直观减少了回调函数和链式 Promise 的复杂性是现代 JavaScript 异步编程的重要特性。
9. promise底层实现
Promise 是 JavaScript 中用于异步编程的一个对象它代表了一个尚未完成但预期将来会完成的操作的最终结果。Promise 可以处于以下三种状态之一待定pending、已成功fulfilled或已失败rejected。以下是 Promise 底层实现的基本概念和步骤 构造 Promise 创建一个新的 Promise 对象时需要提供一个执行器executor函数该函数接收两个参数resolve 和 reject。resolve 函数用于将 Promise 状态更改为已成功传入成功的结果值。reject 函数用于将 Promise 状态更改为已失败传入失败的原因。 异步操作 执行器函数内部执行异步操作如网络请求、文件读写等。根据异步操作的结果使用 resolve 或 reject 来更新 Promise 的状态。 状态变化 当 resolve 或 reject 被调用时Promise 的状态从待定变为已成功或已失败。状态变化后会触发相应的 .then() 或 .catch() 回调函数。 链式调用 Promise 的 .then() 方法返回一个新的 Promise 对象这允许将多个 Promise 操作链接在一起。如果 .then() 或 .catch() 回调函数内部返回一个值这个值会被包装成一个新的 Promise并作为链式调用的下一个 Promise。 错误处理 如果执行器函数抛出异常或者 then 或 catch 回调函数抛出异常Promise 状态会变为已失败并将异常作为失败原因传递。 微任务队列 Promise 的处理通常在微任务microtask阶段执行这意味着在当前任务执行完成后事件循环的下一次迭代之前Promise 的状态变化和回调函数的执行会被处理。
以下是一个简单的 Promise 实现示例
function myPromiseExecutor(resolve, reject) {setTimeout(() {const success true; // 假设异步操作成功if (success) {resolve(Operation successful);} else {reject(Operation failed);}}, 1000);
}const myPromise new Promise(myPromiseExecutor);myPromise.then((result) {console.log(result); // Operation successful},(error) {console.error(error); // Operation failed}
);在这个例子中myPromiseExecutor 函数模拟了一个异步操作myPromise 是一个 Promise 对象它在异步操作完成后调用 resolve 或 reject。.then() 方法用于指定异步操作成功或失败时的回调函数。
Promise 的引入简化了异步编程的复杂性使得异步操作的控制流程更加清晰和易于管理。
11. computea和watch的区别和应用场景
computed 和 watch 是 Vue.js 中的两个响应式系统特性它们都与数据的响应式处理有关但用途和工作方式有所不同。
computed计算属性 用途 computed 属性是基于其他响应式数据动态计算得出的值。它们是派生状态即不需要直接修改 computed 属性的值而是通过修改依赖的数据来间接改变。 工作方式 当依赖的数据发生变化时computed 属性会自动重新计算其值。computed 属性是惰性的只有当它们的依赖项发生改变时才会重新计算。computed 属性具有缓存机制只有当依赖的数据变化时才会重新计算这有助于提高性能。 应用场景 当你需要根据其他数据计算一个新值时例如根据两个输入字段计算结果。当你需要执行复杂逻辑而这些逻辑不应该在模板中直接编写时。
watch侦听属性 用途 watch 允许你观察 Vue 实例上的一个表达式或计算属性函数监听其变化。当被侦听的数据变化时执行一个自定义回调函数。 工作方式 watch 可以侦听所有类型的数据变化包括对象的属性和数组的索引。watch 可以非常精确地控制数据变化时执行的操作例如可以指定深度遍历来侦听对象属性的变化。watch 不具有缓存机制每次数据变化都会执行回调函数。 应用场景 当你需要在数据变化时执行异步操作或较复杂的逻辑时。当你需要在数据变化时执行副作用如滚动到视图顶部、显示消息等时。当你需要侦听多个数据源的变化并根据这些变化执行操作时。
总结
如果你需要根据两个数据属性计算一个新属性那么 computed 是最佳选择。如果你需要在数据变化时执行异步请求或复杂的状态更新那么 watch 将更加合适。
12. js垃圾回收机制
JavaScript的垃圾回收机制是一种自动内存管理机制它负责释放那些不再被使用的内存空间以便这些空间可以被重新分配给新的变量或对象。这是通过垃圾回收器Garbage Collector简称GC来实现的。垃圾回收器在JavaScript中是自动运行的但了解其工作原理对于编写高效和内存优化的代码是非常重要的。
工作原理
JavaScript主要使用两种垃圾回收策略标记-清除Mark-Sweep和分代回收Generational Garbage Collection。 标记-清除Mark-Sweep: 标记阶段垃圾回收器遍历所有的对象从全局对象开始通过引用链找到所有可达的对象并将这些对象标记为“活动”状态。清除阶段垃圾回收器遍历内存删除那些没有被标记为“活动”的对象释放内存空间。 分代回收Generational Garbage Collection: JavaScript的内存被分为几个“代”Generation每个代包含特定生命周期的对象。新生代Young Generation新创建的对象首先被分配在这里。这些对象通常生命周期短频繁创建和销毁。老生代Old Generation长时间存活的对象会被移动到老生代。这些对象通常更稳定不会频繁地被回收。DOM代专门用于存储DOM元素和相关的事件处理器等。
13. 前端缓存机制
前端缓存机制是一种在客户端如浏览器上存储网页数据的技术旨在提高用户体验和网站性能。通过缓存可以减少重复的数据请求加快页面加载速度降低服务器负载并在没有网络连接时提供离线访问的能力。前端缓存主要通过以下几种方式实现
浏览器缓存
浏览器缓存是最常用的前端缓存形式。它利用HTTP协议的缓存控制头部如Cache-Control、Expires、Last-Modified和ETag来确定资源是否可以从本地缓存中加载或者是否需要从服务器重新获取。
Cache-Control这个头部可以指定资源的缓存策略例如no-cache资源可以缓存但每次使用前都需要验证、no-store不缓存、max-age资源在指定时间内有效等。Expires提供一个日期/时间之后资源就被认为是过期的。Last-Modified/ETag服务器可以发送这些头部以便在后续请求中客户端可以通过If-Modified-Since或If-None-Match头部来验证资源是否已经被修改。
Service Workers
Service Workers是一种在用户的浏览器后台运行的脚本它们可以拦截和处理网络请求包括管理缓存。Service Workers使得开发者可以创建自定义的缓存策略即使在没有网络连接的情况下也能够提供离线体验。
Cache APIService Workers使用Cache API来存储和检索请求的响应。Fetch APIService Workers可以监听和处理Fetch事件决定是否直接从缓存中提供响应或者从网络获取数据。
Local Storage 和 Session Storage
这两种Web存储API允许网站存储数据在用户的浏览器中。它们提供了一个简单的键值存储系统可以用于缓存数据。
Local Storage提供没有过期时间的存储数据会一直保留直到被明确清除。Session Storage数据仅在浏览器会话期间存在当浏览器窗口或标签页关闭时数据会被清除。
IndexedDB
IndexedDB是一个低级API用于在用户的浏览器中创建和操作大量结构化数据。它提供了一个异步的、非阻塞的数据库适合于复杂的数据缓存和存储。
应用缓存Application Cache
虽然现在已经被大多数现代浏览器废弃但应用缓存AppCache曾经是一种允许网站离线工作的技术。它通过一个清单文件manifest来定义哪些资源需要缓存以及如何缓存。
缓存策略
有效的前端缓存策略应该考虑数据的更新频率、重要性以及用户对数据新鲜度的需求。例如不经常变化的静态资源如图片、CSS和JavaScript文件可以设置长时间的缓存而频繁更新的内容如新闻文章则应该更频繁地从服务器获取。 如果本文对您有所启发不妨点赞、收藏、关注您的支持是我更新的动力 往期精彩回顾 爆肝五千字ECMAScript核心概念与现代JavaScript特性全解析 878阅读 · 13点赞 · 20收藏 打造精美响应式CSS日历从基础到高级样式 781阅读 · 9点赞 · 13收藏 Ubuntu系统下C语言开发环境搭建与使用教程 764阅读 · 17点赞 · 7收藏 Vue 3响应式系统详解ref、toRefs、reactive及更多 1029阅读 · 23点赞 · 14收藏 爆肝两千字掌握CSS选择器与响应式设计从基础到高级应用 1056阅读 · 27点赞 · 28收藏 图文并茂在Oracle VM VirtualBox上安装Ubuntu虚拟机的详细步骤指南 1087阅读 · 36点赞 · 29收藏 在Vue中使用wangeditor创建富文本编辑器的完整指南 1126阅读 · 20点赞 · 13收藏 Vue项目中使用ECharts构建交互式中国地图的详细指南 781阅读 · 22点赞 · 10收藏 米哈游一面前端开发岗面试题你会做几道? 1237阅读 · 22点赞 · 24收藏