一、原生JS和框架的区别
1.1 代码层面
| 原生JS | 框架 |
|---|---|
| 缺少规划,代码混乱 | 结构化开发 |
| 缺少限制,容易冲突 | 独立文件,独立作用域 |
| 缺少支撑,能力要求高 | 提供支持,只关心业务 |
- 原生JS的代码比较随意,没有规范性,框架对每个页面的代码布局做了规范,有利于可维护性。
- 原生JS开发不是多人并行开发的,若修改代码很容易造成全局变量和其他业务发生变化,而框架使用webpack等打包工具,实现了各页面的独立开发,相互不影响,有自己独立的作用域,和其他页面不会产生冲突,解决了多人并发开发的问题。
- 原生JS所有的架构,使用工具都需要手动编写,框架将大部分工具封装好了,直接用。
1.2 效率问题
| 原生JS | 框架 |
|---|---|
| 关注所有流程 | 只关注业务 |
| 团队效率低 | 并行开发 |
| 测试效率低 | 模块测试,自动化测试 |
- 原生JS开发者需要关注所有流程,还不能并行开发,效率很低,框架使得开发者仅仅只需要关注业务逻辑的实现,不需要关注其他,提高了效率
- JS的影响是全局的,团队开发效率太低,框架的修改只会影响自己的模块,不会影响他人,可以多人开发。
二、Vue的生命周期
Vue的生命周期主要有:
- 创建 —— 在组件创建之前执行
- 挂载 —— DOM被挂载时执行
- 更新 —— 当响应数据被修改时执行
- 销毁 —— 在元素被销毁之前立即执行
并且每个生命周期被分为了两个钩子。
| Vue2 | Vue3 |
|---|---|
| beforeCreate | setup() |
| created | setup() |
| beforeMount | onBeforeMount |
| mounted | onMounted |
| beforeUpdate | onBeforeUpdate |
| updated | onUpdated |
| beforeDestroy | onBeforeUnmount |
| destroyed | onUnmounted |
| errorCaptured | onErrorCaptured |
三、Vue的双向绑定原理
1.作用在表单上时,动态绑定了input的value指向了searchText,并在触发了input事件的时候动态把searchText设置为目标值:
<input v-model="searchText">
//可以等价为以下方式
<input
:value="searchText"
@input="searchText = $event.target.value"
/>
- 作用在组件上,v-modek默认会利用名为value的prop和名为input的事件,本质是一个父子组件通信语法糖,通过prop和$emit实现。
<CustomInput v-model="searchText" />
//展开如下:
<CustomInput
:modelValue="searchText"
@update:modelValue="newValue => searchText = newValue"
/>
//组件内部如下:
<!-- CustomInput.vue -->
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>
<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>
四、组件之间通信方式
4.1 props/$emit(父子通信)
父组件通过props进行定义一个参数传给下一个子组件,子组件用$emit绑定一个自定义事件,当这个事件被执行的时候就会将参数传递给父组件,而父组件通过v-on监听并接收参数。
4.2 provide/inject(父子,祖孙)
该方法可以用于父子、祖孙组件之间的通信。
provide钩子用来发送数据或方法inject钩子用来接收数据或方法
4.3 eventBus事件总线、Vuex(任意组件通信)
该方法是Vue2独有的方法,Vue3移除。
-
使用 eventBus ,其实就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。
-
$emit向其他组件传递参数 -
$on接收其他组件传递参数
也可以使用Vuex进行全局管理。
五、响应式原理
Vue2---Object.defineProperty
Vue2在实例初始化时遍历data中的所有属性,并使用Object.defineProperty把这些属性全部转为getter/setter。并劫持各个属性getter和setter,在数据变化时发布给消息订阅者,触发相应的监听回调。
有以下缺点:
-
初始化时需要遍历对象所有 key,如果对象层次较深,性能不好
-
通知更新过程需要维护大量 dep 实例和 watcher 实例,额外占用内存较多
-
Object.defineProperty 无法监听到数组元素的变化,只能通过劫持重写数方法
-
动态新增,删除对象属性无法拦截,只能用特定 set/delete API 代替
-
不支持 Map、Set 等数据结构
Vue3---Proxy
Vue3使用Proxy来监控数据变化。Proxy是ES6中提供的功能,其作用为:定义基本操作的自定义行为。其有以下特点:
-
Proxy 直接代理整个对象而非对象属性,这样只需做一层代理就可以监听同级结构下的所有属性变化,包括新增属性和删除属性。
-
它的处理方式是在 getter 中去递归响应式,这样的好处是真正访问到的内部属性才会变成响应式,简单的可以说是按需实现响应式,减少性能消耗。
-
Proxy 可以监听数组的变化。
六、计算属性computed和Watch属性
6.1 computed
- 它支持缓存,只有当依赖的数据发生了变化,才会重新计算
- 不支持异步,当Computed中有异步操作时,无法监听数据的变化
- computed的值仅会在其响应式依赖更新时才重新开始计算
- computed属性一般为只读的,其内部有get和set算法,默认使用get方法,当数据变化时使用set
6.2 watch
-
它不支持缓存,数据变化时,它就会触发相应操作
-
支持异步监听
-
监听的函数接收两个参数,第一个参数是最新的值,第二个是变化之前的值,当一个属性发生变化时,就需要执行相应的操作。
-
监听数据必须是data中声明的或者从父组件传递过来的数据,当发生变化时,函数有两个参数:
- immediate:组件加载立即触发回调函数
- deep:深度监听,发现数据内部的变化,在复杂数据类型中使用,例如数组中的对象发生变化。需要注意的是,deep无法监听到数组和对象内部的变化。
七、Vue2和Vue3的区别
7.1 监听机制的改变
Vue3使用的是Proxy对数据进行代理,消除了Vue2Object.defineProperty的很多限制,Vue3可以监听到对象属性的添加和删除,可以监听数组的变化,还有Map、Set、WeakMap、WeakSet。
7.2 API模式不同
Vue2采用的是选项式API,Vue3采用组合式API。Vue3可以更好的组织和重用逻辑代码,更利于维护。
7.3 生命周期勾子不同
具体情况见上。
7.4 Typescript支持
Vue3 对 TypeScript 的支持更加完善,可以提供更好的类型检查和错误提示。
总之,Vue3 在性能、代码组织、类型检查和数据响应式等方面都有所改进和优化,可以提供更好的开发体验和性能。
八、Vue-Router
8.1 hash模式和history模式
Hash路由
Hash路由是指路由信息存放在URL的hash部分,即#后面的内容。在使用hash路由时,浏览器的URL不会向服务器发起请求,只是对URL进行了修改,因此不会刷新页面。通过监听hashchange事件,可以在hash改变时更新页面内容。
Hash路由的特点:
- hash改变不会导致页面刷新,用户体验较好。
- hash不会被包含在HTTP请求中,对后端不会产生影响。
- 支持浏览器前进、后退操作。
History路由
History路由是指路由信息存放在URL的路径部分。在使用history路由时,URL发生变化会向服务器发起请求,服务器需要返回对应的页面内容。通过history API可以实现前进、后退等功能。
History路由的特点:
- 可以使用HTTP请求来获取页面内容,但每次URL发生变化时都会向服务器发起请求,会影响性能。
- 支持浏览器前进、后退操作。
综合来说,hash路由适合实现单页面应用(SPA),而history路由适合多页面应用。
为什么history模式会有404问题?
在使用history模式时,由于服务器端没有相应的路由配置,当用户在地址栏输入一个路由地址时,服务器无法匹配到对应的资源,因此会返回404。因此,需要在服务器端进行配置,将所有的路由都指向一个入口文件,然后在该入口文件中通过路由管理器根据不同的 URL 显示相应的内容。
为什么hash模式没有404问题?
在使用 hash 模式时,URL 中的 hash(即 # 后面的部分)被当做是客户端的内部资源,不会被发送到服务器端。因此,无论用户在地址栏输入什么样的 hash 路径,服务器都不会返回 404 错误,因为服务器根本不会对 hash 路径进行处理。
相对于 history 模式而言,hash 模式的优点是可以避免在服务器端配置通配符路由。但是,由于 hash 的存在,每次路由切换时都会在 URL 中添加新的 hash,可能会让 URL 看起来比较混乱。同时,在 SEO 优化方面也会有一些问题,因为搜索引擎不会将 hash 作为独立的 URL 处理,导致无法将 hash 路径索引到搜索结果中。