View / MVVM 框架
如何实现一个组件,前端组件的设计原则是什么?
- 单一原则:一个组件只做一件事
- 通过脑图、结构图,标识组件的 State Props Methods 生命周期,表示层次和数据流动关系
- State 和 Props。
- 扁平化:最多使用一层嵌套,便于对比数据变化,代码更简洁。
- 无副作用:State 仅响应事件,不受其他 State 变化影响
- 松耦合,
- 组件应该独立运行,不依赖其它模块
- 配置、模拟数据、非技术说明文档、helpers、utils 与组件代码分离
- 视图组件只关心视图,数据获取,过滤,事件处理应在外部 JS 或 父组件中处理
- Kiss原则(Keep it Simple Stupid)
- 不需要 State 时,使用 函数组件。
- 不要传递不需要的 Props。
- 及时抽取复杂组件为独立组件。
- 不要过早优化
- 参考 CSS 的 OOSS 方法论,分离 位置 和 样式,利于实现皮肤
- 考虑 多语言、无障碍 等后期需求
对比 React 、Angular 和 Vue
该问题 Vue 官方在 《对比其他框架》 中作过说明,整理如下:
- React 和 Vue都提供了 Virtual Dom
- 提供了 响应式(Reactive)和组件化(Composable)的视图组件
- 注意力保持在核心库,而将其他功能如路由和全局状态管理交给相关的库
渲染优化
- React:当组件状态发生变化时,以该组件为根,重新渲染整个组件子树
- shouldComponentUpdate,采用合适方式,如不可变对象,比较 props 和 state,决定是否重新渲染当前组件
- 使用 PureComponent:继承自 Component 类,自动加载 shoudComponentUpdate 函数,自动对 props 和 state 浅比较决定是否触发更新
- Vue:自动追踪组件依赖,精确渲染状态改变的组件
https://www.zhihu.com/question/301860721
https://www.zhihu.com/question/66749082/answer/246217812
HTML 和 CSS
- React:支持 JSX
- 在构建视图时,使用完整的 JavaScript 功能
- 开发工具多支持 JSX 语法高亮,类型检查和自动完成
- Vue:提供渲染函数,支持 JSX,但默认推荐 Vue 模版
- 与书写 HTML 更一致的开发体验
- 基于 HTML 的模版更容易迁移到 Vue
- 设计师和新人开发者更容易理解和参与
- 支持模板预处理器,如 Pug
CSS 作用域
- React:普通的css(组件作用域问题),到css modules(需要使用style.className}),再到css in js,如 styled-components 和 emotion,
- Vue:
- 支持 CSS-in-JS 方案,如 styled-components-vue 和 vue-emotion
- 单文件组件中 style 标签可选 scoped 属性。支持 Sass \ Less \ Stylus 等 CSS 预处理器,深度集成 CSS Modules
规模、向上扩展:
React:
- 路由库和状态管理库,由社区维护支持,生态松散且繁荣
- 提供脚手架工具,故意作了限制
- 不允许在项目生成时进行配置
- 只提供一个单页面应用模板
- 不支持预设配置
Vue:
- 路由库和状态管理库,由官方维护支持,与核心库同步更新
- 提供 CLI脚手架,可构建项目,快速开发组件的原型
- 允许在项目生成时配置
- 提供了各种用途的模板
- 支持预设配置
向下拓展
- React:学习曲线陡峭,需要前置知识:JSX ES2015,需要学习构建系统
- Vue:既支持向上拓展与 React 一样,也支持向下拓展与 jQuery 一样,上手快
原生渲染
- React Native:使用相同组件模型编写具有本地渲染能力的APP,跨平台开发
- Weex:阿里巴巴发起,Apache 基金会孵化,同样支持本地渲染,跨平台开发,NativeScript-Vue,基于 Vue.js 构建原生应用的 NativeScript 插件
MobX
- React:流行的状态管理框架
- Vue:选择 Vue 比 React + MobX 更合理
Vue 和 React 实现复用
这个方面我觉得也没有复述的必要,因为在实现复用的道路上,Vue 和 React 都是经历了:Mixin -> Hoc(Vue 比较少用,模版套模版,有点奇怪了)-> render prop(Vue 有类似思想的实现为 slot) -> hooks(Vue3.0 function based API)在这方面,UI 层面的复用本身不是问题:因为组件化本身就是天然可组合的。重要的是逻辑复用:hooks 和 Vue3.0 function based API 的设计无疑是最先进的,它将逻辑复用和组件表达在一定程度上解耦,避免了“面向生命周期编程”的困扰。顺便达到了更好的组合性和 TS 友好性。
VUE
computed 与 watch 的区别?
https://www.cnblogs.com/sunflower-js/p/15786074.html
computed
- 支持数据缓存
- 内部数据改变也会触发
- 不支持异步,异步无效
- 适用于 一个属性由其他属性计算而来,依赖其他属性的场景
watch
- 不支持数据缓存
- 可以设置一个函数,带有两个参数,新旧数据
- 支持异步
- 监听数据必须是 data 中声明过或者父组件传递过来的 props 中数据
- immediate:组件加载立即触发回调函数执行
- deep:深度监听
Vue.nextTick 原理和作用?
- Vue 异步执行 DOM 更新,观察数据变化,开启队列缓冲同一事件循环中所有数据改变
- 同一个 watcher 被多次触发,只会被推入到队列中一次,避免不必要的计算和 DOM 操作
- 在下一个事件循环 tick 中,Vue 刷新队列并执行实际(已去重)工作
- 异步队列使用 Promise.then 和 MessageChannel,不支持环境使用 setTimeout(fn, 0)
- 在需要立即更新 DOM 的场景中使用
Vue3.x 的新特性
API 风格
- Vue2.x:Options API
- Vue3.x:Composition API
组件生命周期
Vue2.x:
- beforeCreate
- created
- beforeMount
- mounted
- beforeUpdate
- updated
- beforeDestroy
- destroyed
- activated
- deactivated
- errorCaptured
Vue3.x:
- setup
- onBeforeMount
- onMounted
- onBeforeUpdate
- onUpdate
- onBeforeUnmout
- onUnmounted
- onActivated
- onDeactivated
- onErrorCaptured
- onRenderTriggered
- onRenderTracked
指令生命周期
Vue2.x:
- bind
- inserted
- update
- componentUpdated
- unbind
Vue3.x:
- beforeMount
- mounted
- beforeUpdate
- updated
- beforeUnmount
- unmounted
数据
- Vue2.x:data
- Vue3.x
- ref 基础类型和对象的双向绑定
- reactive 对象的双向绑定
- 通过
toRefs
转为 ref
- 通过
监听
- Vue2.x:watch
- Vue3.x:watchEffect
- 传入回调函数,不需要指定监听的数据源,自动收集响应式数据
- 可以从回调函数中,获取数据的最新值,无法获取原始值
slot
- Vue2.x:通过
slot
使用插槽,通过slot-scope
给插槽绑定数据 - Vue3.x:
v-slot:
插槽名=
绑定数据名
v-model
- Vue2.x:.async 绑定属性和 update:+ 属性名 事件
- Vue3.x:无需 .async 修饰
新功能
- Teleport:适合 Model 实现
- Suspense:
- 一个组件两个 template
- 先渲染 #fallback 内容,满足条件再渲染 #default
- 适合异步渲染显示加载动画,骨架屏等
- defineAsyncComponent:定义异步组件
- 允许多个根节点
性能
- 使用 Proxy 代替 definePoperty 和 数组劫持
- 节点类型,diff 时,跳过静态节点
- 支持 ES6 引入方法,按需编译
- 配套全新的 Web 开发构建工具 Vite
React
React 中有哪几种类型的组件,如何选择?
无状态组件
- 更适合函数组件
- 负责展示
- 无状态,复用度高
有状态组件
- 函数组件 + hooks 或 类组件
- useState 或 声明 state
- useEffect 或 使用生命周期
容器组件
- 子组件状态提升到此,统一管理
- 异步操作,如数据请求等
- 提高子组件的复用度
高阶组件
- 接收组件,返回组件
- 为原有组件增加新功能和行为
- 代替 mixins,避免状态污染
回调组件
- 高阶组件的另一种形式
- 将组件本身,通过 props.children 或 prop 属性 传递给子组件
- 适合不能确定或不关心传给子组件数据的场景,如路由,加载组件的实现
对比 React 和 Vue 的 diff 算法?
相同点
- 虚拟 Dom 只同级比较,不跨级比较
- 使用 key 标记和复用节点,不建议使用数组索引 index 作为 key
不同点
- 顺序
-
- Vue:两端到中间
- React:从左到右
- 节点元素类型相同,ClassName 不同
- Vue:不同类型元素,删除重新创建
- React:相同类型元素,修改
节点类型
- Vue 3.x:VNode 创建时,即确定类型
React 中使用 useEffect 如何清除副作用?
在 useEffect 中返回一个清除函数,名称随意,可以是匿名函数或箭头函数,在清除函数中添加 处理副作用的逻辑,如移除订阅等查看代码
function component(props) {
function handleStatusChange(status) { console.log(status.isOnine) }
useEffect(() => {
API.subscribe(props.id, handleStatusChange))
}
return function cleanup() {
API.unsubscribe(props.id, handleStatusChange)
}
}
javaScript
Es3
常见的类型转换
a = ?, a==1 && a==2 && a==3 成立
==
会触发隐式转换,===
不会对象转字符串: 先toString(), 再valueOf()对象转数字: 先valueOf() 或者 toString() + valueOf()
对象转布尔, True
数组转对象: 符合对象规律,不过toString()里面会调用join()方法
可以直接在定义处重写方法
对比 get 和 Object.defineProperty
-
get
属性将被定义到 实例原型 -
Object.defineProperty
属性将被定义在 实例自身
查看代码
class TestGet {
#name;
constructor (name) {
this.#name = name;
}
get name () {
return 'njvnj';
}
}
const a = new TestGet('jkl');
const test = Object.create({});
Object.defineProperty(test, 'name', {
get: () => {
return this.name;
},
set: (name) => {
this.name = name + ' word!';
}
})
test.name = 'hello'
console.log(test.name);
对比 escape encodeURI 和 encodeURIComponent
escape
对字符串编码
ASCII 字母、数字 @ * / + - _ . 之外的字符都被编码
encodeURI
对 URL 编码
ASCII 字母、数字 @ * / + 和 ~ ! # $ & () =, ; ?- _ . '之外的字符都被编码
encodeURIComponent
对 URL 编码
ASCII 字母、数字 ~ ! * ( ) - _ . ' 之外的字符都被编码