Vue2和Vue3的区别
双向数据绑定原理不同
Vue2 的双向数据绑定是利用ES5的一个APIObject.definePropert()
对数据进行劫持,结合发布订阅模式的方式来实现的。Vue3 中使用ES6的Proxy API
对数据代理。Vue2 不支持碎片。Vue3 支持碎片,就是说可以拥有多个根节点
API 类型不同
(1) Vue2 使用选项类型api,在代码里分割了不同的属性:data,computed,method等。
(2) Vue3 使用合成型api, 能让我们使用方法来分割,相比于旧的api 使用属性来分组,这样代码会更加简便和整洁。定义数据变量和方法不同
Vue2是把数据放到了data 中,在 Vue2中 定义数据变量是data(){},创建的方法要在method:{}
Vue3 就需要使用一个新的setup()方法,此方法在组件初始化构造的时候触发,设立响应式数据:1)从vue 引入 reactive;2)使用 reactive ()方法来声明数据为响应性数据;3) 使用setup()方法来返回我们的响应性数据,从而template 可以获取这些响应性数据。-
生命周期钩子函数不同
Vue2 中的生命周期:beforeCreate 组件创建之前;created 组建创建之后;beforeMount 组件挂载到页面之前执行;Mounted 组件挂载到页面之后执行,beforeUpdate 组件更新之前;updated组件更新之后
Vue3 中的生命周期:setup 开始创建组件;onBeforeMount 组件挂载到页面之前执行;onMounted 组件挂载到页面之后执行;onBeforeUpdate 组件更新之前;onUpdated 组件更新之后;而且 Vue3 生命周期在调用前需要先进行引入。除了这些钩子函数外,Vue3 还增加了 onRenderTracked 和onRenderTriggered 函数。
父子传参不同
Vue2 父传子,会调用this$emit 然后传入事件名和对象。
Vue3 父传子,在Vue3 中的setup()中的第一参数content 对象中就有 emit,那么我们只要在setup()接收第二个参数中使用分解对象法取出emit 就可以在setup 方法中随意使用了。指令与插槽不同
Vue2 中使用slot 可以直接使用slot ;v-for 与v-if 在Vue2中优先级高的是v-for 指令,而且不建议一起使用。
Vue3 中必须是使用v-slot的形式;vue 3中v-for 与v-if ,只会把当前v-if 当作v-for 的一个判断语句,不会相互冲突;
Pinia和Vuex 区别
Vuex和Pinia都是用于状态管理的库,但它们有一些区别。
- 架构设计:Vuex是Vue.js官方提供的状态管理库,而Pinia是由Vue作者维护的另一个状态管理库。Vuex采用了集中式的架构,将所有的状态存储在一个单一的全局状态树中,通过mutations和actions来修改和处理状态。而Pinia采用了去中心化的架构,将状态分布在多个模块中,每个模块拥有自己的状态、mutations和actions。,它专注于提供一个简单的API来管理应用程序的状态。相比之下,Vuex是一个更完整的状态管理库,它提供了更多的功能,比如模块化、插件和严格模式等。Pinia是基于Vue 3的Composition API构建的。
体积和复杂性:由于Vuex是Vue.js的官方状态管理库,它在Vue.js项目中广泛使用,并拥有庞大的生态系统。相比之下,Pinia是一个相对较新的库,较小且更简单。这使得Pinia在一些小型或简单的项目中可能更容易上手,而Vuex则更适合大型和复杂的项目。
TypeScript 支持:在类型安全性方面,Vuex从Vue 2.x版本开始引入了对TypeScript的支持,但需要使用额外的插件来实现类型检查。而Pinia在设计之初就对TypeScript提供了原生的支持,提供了更好的类型推导和类型检查的支持。
代码风格和语法:Vuex使用了更传统的mutations和actions的方式来修改和处理状态,而Pinia更加倾向于直接操作状态。
Vue Router如何实现?如何匹配路径分发组件?
https://blog.csdn.net/weixin_42122355/article/details/117968861
https://wenku.baidu.com/view/93c3c8db834d2b160b4e767f5acfa1c7ab008221.html?wkts=1709687718511&bdQuery=Vue+Route%E5%A6%82%E4%BD%95%E5%8C%B9%E9%85%8D%E8%B7%AF%E5%BE%84%E5%88%86%E5%8F%91%E7%BB%84%E4%BB%B6%3F&needWelcomeRecommand=1
<Keep-alive>保存的是什么?内部子组件状态会保留吗?会执行生命周期吗?
<keep-alive>
是 Vue.js 提供的一个抽象组件,用于缓存其内部的子组件状态而不销毁它们。当子组件被包裹在 <keep-alive> 组件内时,Vue.js 会将这些子组件缓存起来,而不是每次切换时销毁和重新创建子组件。
<keep-alive> 保存的内容:
组件状态:<keep-alive> 会保存子组件的状态,包括数据、DOM 状态和子组件的实例。
DOM 元素:子组件的 DOM 结构也会被保留在内存中,这样在重新激活时可以直接显示,而不需要重新渲染。
内部子组件状态保留:
内部子组件状态会保留:在 <keep-alive> 包裹的子组件中,子组件的状态会得到保留,包括数据、计算属性等,在切换到该子组件时,不需要重新初始化和获取数据。
子组件生命周期钩子执行:
- activated 生命周期钩子:当组件在 <keep-alive> 中被激活时(被切换到),会触发activated生命周期钩子,可以在这个钩子中执行需要在组件显示时进行的操作。
- deactivated 生命周期钩子:当组件在 <keep-alive> 中被停用(被切换出去)时,会触发deactivated生命周期钩子,可以在这个钩子中执行需要在组件隐藏时进行的操作。
<keep-alive> 对内部子组件的状态进行了缓存,可以节省资源和提高性能,同时能够保留子组件的状态和 DOM 结构,在特定情况下可以避免了频繁的初始化和渲染操作。
Computed值什么时候变化
computed是vue的计算属性,是根据依赖关系进行缓存的计算,只有在它的相关依赖发生改变时才会进行更新。
computed的每一个计算属性都会被缓存起来,只要计算属性所依赖的属性发生变化,计算属性就会重新执行,视图也会更新。
应用场景:
当一个数据受多个数据影响时,可以使用computed
1.本组件计算
2.计算props的值
3.计算vuex的state或者getters值的变化
如何优化Vue的性能
一、渲染优化
v-for
避免v-if和v-for的同级使用,v-for的优先级比v-if高,会导致数据渲染错误
v-for设置key的值,尽量不适用index,使用数据中唯一的标识,有利于dom的定位与diff。v-show和v-if的选择
经常复用的组件用v-show来渲染(v-show是隐藏不销毁)
相反则用v-if(直接判断是否创建)长列表优化
纯粹做数据展示,不需要热更新
处于data中的数据会被监视,发生变化时数据就发生变化
所以采用object.freeze(数据)方法冻结数据。长列表
采用虚拟滚动,只渲染少部分区域的内容
只渲染视口部分的数据,也就是说渲染的DOM节点个数是固定的
自己封装:
数据一次性给:
元素监听scroll事件(滚动事件)
计算可视化高度一次能装几个列表,然后从总数据中进行slice截取
每一次滚动后根据scrollTop值获取一个可以整除itemH结果进行偏移(scrollTop:滚动条移动的距离)
- keep-alive缓存页面
- 减少后台访问
- 路由懒加载
- 图片懒加载
Token、Cookie、Session、LocalStorage 的介绍及区别:
-
Token:
- 定义:Token是一种用于身份验证和授权的令牌,通常由服务器颁发给客户端,并在客户端持有。
- 使用:Token通常被放置在请求的头部(Header)中,用于验证用户的身份,可以用于实现用户认证和授权。
- 特点:Token通常是无状态的,服务器不会在后端存储Token,而是由客户端携带Token以完成验证过程。
-
Cookie:
- 定义:Cookie是在客户端存储的一小段文本信息,由服务器发送给浏览器,浏览器会将Cookie保存在客户端。
- 使用:主要用于跟踪用户的会话状态、存储用户偏好设置等。
- 特点:Cookie可以设置过期时间,可以在浏览器和服务器之间来回传递数据。
-
Session:
- 定义:Session是在服务器端存储的关联用户会话的信息,通常通过唯一的标识符来绑定用户的会话。
- 使用:用于保持用户会话状态,存储用户登录状态、数据等。
- 特点:Session存储在服务器端,相对于Cookie更安全,但会占用服务器资源。
-
LocalStorage:
- 定义:LocalStorage是浏览器提供的一种用于存储较大量数据的机制,存储在客户端浏览器中,数据不会失效。
- 使用:用于本地存储数据,持久保存在客户端浏览器中。
- 特点:LocalStorage数据保留在浏览器中,跨页面和刷新后数据依然存在,不会随着会话结束而失效,比较适合长期存储。
-
区别:
- 位置:Token、Cookie、LocalStorage存储在客户端,Session存储在服务器端。
- 生命周期:Cookie和LocalStorage有时效期限,Session在一定时间内有效,Token通常不过期。
- 容量:Cookie的存储容量有限,LocalStorage相对较大,Session取决于服务器资源的限制,Token不占用服务器资源。
- 安全性:Token相对较安全,Cookie存在安全性问题,Session相对安全,LocalStorage较为易受 XSS 攻击。
- 跨域:Token可以跨域使用,Cookie的跨域有限制,Session一般不跨域,LocalStorage是域名限定的。
原生JS绑定的点击事件
可以使用addEventListener()函数来添加点击事件的处理程序,
addEventListener()函数:
第一个参数event:监听的事件名称
第二个参数是函数:需要执行的事件
第三个参数是useCapture(变量):用来判断是捕获还是冒泡
1)当useCapture为true的时候是在捕获阶段触发事件 (捕获事件触发顺序是由父到子)
2)当useCapture为false的时候是在冒泡阶段触发事件(默认为false)(冒泡事件触发顺序是由子到父)
3)第三个参数不一定是 bool 值,也可以是个对象,它提供了更多选项。
once:只执行一次。
passive:承诺此事件监听不会调用 preventDefault,这有助于性能。
useCapture:是否捕获(否则冒泡)。
事件冒泡和事件捕获
冒泡事件:事件由子元素传递到父元素的过程叫做冒泡
捕获事件:事件由父元素传递到子元素的过程叫做事件捕获
阻止冒泡与阻止默认
1.阻止冒泡就是让我们的层级事件不再触发,在点击子级时,父级不会触发点击事件。一般我们使用e.stoppropagation();来阻止冒泡。
2.阻止默认:一般我们在文档中想复制一些文字,按住就可以勾选,但是当我们使用了阻止默认,内容就无法勾选。通常我们使用e.preventDefault()方法来阻止默认。
3.总结:e.stoppropagation()阻止冒泡 e.preventDefault()阻止默认 return false;既阻止冒泡又阻止默认。
onclick和addEventListener('click',handler)的区别
1.addEventListener可以同时绑定多个事件,onclick只能绑定一个
2.addEventListener我们可以决定DOM事件的触发是以事件捕获的事件流还是事件冒泡的事件流方式
3.onclick移除事件直接等于null即可,但addEventListener
需要div.removeEventListener
HTTP 状态码:
HTTP 状态码是作为 HTTP 协议的一部分,用于指示客户端和服务器之间请求的处理情况。以下是常见的 HTTP 状态码类别及其含义:
1xx - 信息性状态码:
100 Continue:服务器已接收请求的初始部分,等待客户端继续发送其余部分。
101 Switching Protocols:服务器已切换协议,客户端应切换到新协议。2xx - 成功状态码:
200 OK:请求成功。
201 Created:请求已经被创建。
204 No Content:没有返回内容。3xx - 重定向状态码:
301 Moved Permanently:请求的资源已经被永久移动到新的位置。
302 Found:请求的资源临时移动到新的位置。
304 Not Modified:资源未修改,仍可使用缓存版本。4xx - 客户端错误状态码:
400 Bad Request:请求无效。
401 Unauthorized:请求未经授权。
403 Forbidden:禁止访问。
404 Not Found:资源未找到。5xx - 服务器错误状态码:
500 Internal Server Error:服务器内部错误。
502 Bad Gateway:网关错误。
503 Service Unavailable:服务不可用。
504 Gateway Timeout:网关超时。
Vue循环时绑定的key有什么作用
- 性能优化:Vue 使用 key 来最小化 DOM 的操作,有助于提高列表的性能。使用 key 可以告诉 Vue 哪些元素是已经存在的、新增的或被移除的,从而帮助 Vue 优化列表的渲染过程。
- 维护组件状态:设置 key 可以帮助 Vue 识别每个列表项,从而在列表重新渲染时保留组件的状态。如果不为列表项设置 key,在列表变化时可能会导致组件的状态丢失或混乱。
- 唯一性:key 必须在同一级的兄弟元素中具有唯一性,确保 Vue 能够正确地识别每个列表项,准确地跟踪列表项的变化。
redux
1.redux 是一个独立专门用于做状态管理的 JS 库(不是 react 插件库)
2.它可以用在 react, angular, vue 等项目中, 但基本与 react 配合使用
3.作用: 集中式管理 react 应用中多个组件共享的状态
- redux与Vuex的区别
vuex定义了state、getter、mutation、action四个对象;redux定义了state、reducer、action。
vuex触发方式有两种commit同步和dispatch异步;redux同步和异步都使用dispatch
Redux 使用的是不可变数据,而Vuex的数据是可变的。Redux每次都是用新的state替换旧的state,而Vuex是直接修改
Redux 在检测数据变化的时候,是通过 diff 的方式比较差异的,而Vuex其实和Vue的原理一样,是通过 getter/setter来比较的
防抖和节流
防抖 :指在一定时间内,多次触发同一个事件,只执行最后一次操作。使用防抖技术,将一定时间内的多次触发合并为一次操作,只请求一次服务器数据,减少了请求次数和服务器负载。
节流 :指在一定时间内,多次触发同一个事件,只执行第一次操作。例如,当我们拖动网页上的滚动条时,会不断触发 onscroll 事件,如果每次触发都去计算滚动距离,会造成浏览器性能下降。此时就可以使用节流技术,将一定时间内的多次触发限制为一次操作,只计算一次滚动距离,提高了浏览器性能和用户体验。
防抖的应用场景:
1. 搜索框实时搜索:在搜索框中输入关键词时,防抖可以延迟请求发送,只在用户输入完成或者停顿一段时间后才触发实际的搜索请求,避免频繁的网络请求。
2. 窗口大小调整:当用户调整浏览器窗口大小时,窗口大小变化事件会连续触发,使用防抖可以确保只在用户完成调整后再执行相应的响应逻辑,以避免过多的布局计算。
节流的应用场景:
1. 页面滚动加载:在无限滚动的页面中,滚动事件会频繁触发,使用节流可以控制数据加载的频率,防止短时间内多次加载数据,提高页面加载性能。
2. 按钮防重复点击:当用户点击按钮执行某个操作时,使用节流可以确保按钮在一定时间内只能触发一次,防止用户重复点击造成误操作。
JS的事件循环
JavaScript事件循环是一种处理异步事件和回调函数的机制,它是JavaScript实现异步编程的核心。JavaScript事件循环是为了解决JavaScript作为单线程语言时的并发性问题而设计的,引入了异步编程模型和事件循环机制,它可以监听消息队列中的事件并根据优先级顺序依次执行相应的回调函数。
这种机制允许JavaScript在等待某些操作完成的同时,可以执行其他任务,从而避免了阻塞,提高了效率和并发性。
JavaScript的事件循环是一种用于管理执行长期运行任务的机制,它允许浏览器处理用户交互、DOM事件、setTimeout回调和其他异步任务,而不会阻塞UI。
事件循环基本步骤如下:
检查宏任务队列(如setTimeout的回调、setInterval的回调、用户输入、UI交互等)。执行一个宏任务。
检查微任务队列(如Promise的回调、MutationObserver的回调等)。执行所有微任务。
返回步骤1,重复这个过程,直到宏任务队列和微任务队列都为空。
如何实现响应式对象
响应式:可以自动响应数据变量的代码机制,如:当有一个值发生了变化,引用了这个值的地方会自动重新执行
将一个普通对象转为一个响应式对象,即通过reactive函数,他接收一个普通对象,返回的是一个proxy对象。
在reactive函数中,需要用到porxy的两个捕获器get与set,get是用来收集依赖的,当我们对象的某个属性值变化时,我们可以在set捕获器中捕获到,让他重新执行需要响应的函数
不管我们set还是get,我们都需要找到,对应的依赖来执行,所以我们需要用一个合适的数据结构来存取我们对应的依赖(数据结构:WeakMap中的属性名是对象,值为map map中的属性名是对象的属性名,值为new Depend())
// 当前需要收集的响应式函数
let activeReactiveFn = null
// 响应式的函数
function watchFn(fn) {
activeReactiveFn = fn
fn()
activeReactiveFn = null
}
// 依赖类
class Depend {
constructor() {
// 依赖容器
this.reactiveFns = new Set()
}
// 添加依赖的方法
depend() {
activeReactiveFn && this.reactiveFns.add(activeReactiveFn)
}
// 执行依赖的方法
notify() {
this.reactiveFns.forEach(fn => {
fn()
})
}
}
// 获取当前依赖 数据结构:WeakMap中的属性名是对象,值为map map中的属性名是对象的属性名,值为new Depend()
const targetMap = new WeakMap()
function getDepend(target, key) {
let map = targetMap.get(target)
if (!map) {
map = new Map()
targetMap.set(target, map)
}
let depend = map.get(key)
if (!depend) {
depend = new Depend()
map.set(key, depend)
}
return depend
}
// 将对象变为响应式
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
// 收集依赖
const depend = getDepend(target, key)
depend.depend()
return Reflect.get(target, key, receiver)
},
set(target, key, newValue, receiver) {
Reflect.set(target, key, newValue, receiver)
// 获取当前依赖,并重新执行
const depend = getDepend(target, key)
depend.notify()
}
})
}
const infoProxy = reactive({
name: "xt", // depend对象
age: 18 // depend对象
})
// 当infoProxy.address变化时需要执行的代码 当其首次执行行 我们需要收集依赖
watchFn(() => {
console.log(infoProxy.name)
})
watchFn(() => {
console.log(infoProxy.age)
})
infoProxy.name = "tx"
infoProxy.name = "20"
单项数据流和双向数据流绑定
单向数据流:是指数据在应用程序中的流动方向是单向的,从父组件流向子组件,而不会反向流动。数据的更新只能通过父组件对子组件进行传递,子组件无法直接更改父组件的数据。如:vue的props
双向数据绑定:允许数据在父子组件之间进行双向的同步更新。当一个组件的数据发生改变时,双向数据绑定会自动更新其他相关的组件。
vue支持单向绑定和双向绑定
单向绑定:插值形式{{data}},v-bind也是单向绑定
双向绑定:表单的v-model,用户对View层的更改会直接同步到Model层
组件通信
实现组件通信的方式:
- 父组件 → 子组件 :props
- 子组件 → 父组件 :emit 可以实现子给父通信即vm.$emit( event, arg )
- 全局事件总线eventBus:$bus 全能:在两个组件中通过分别调用这个实例的事件触发和监听来实现通信。
import Bus from 'eventBus.js';
sayHello() {
Bus.$emit('sayHello', 'hello');
}
import Bus from 'eventBus.js';
Bus.$on('sayHello', target => {
console.log(target); // => 'hello'
});
- 插槽 :子组件中的提供给父组件使用的一个占位符,用<slot></slot> 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的<slot></slot>标签。
- Vuex
action和mutation
在 Vuex 中,action 和 mutation 是用来管理应用状态的两个重要概念,它们有以下区别:
-
Mutation:
- 作用:Mutations 是 Vuex 中用于修改状态的唯一方法,它们是同步的函数。
- 使用场景:通常在 Mutations 中进行简单的状态更改,如更新 state 的值。
- 规范:Mutations 必须是纯函数(Pure Functions),即给定固定的输入,每次返回固定的输出,不应该有副作用。
- 调用方式:通过 commit 方法触发 Mutations 的调用。
-
Action:
- 作用:Actions 用于处理异步操作、逻辑处理或批量触发多个 Mutations,它们是异步的函数。
- 使用场景:在 Actions 中可以包含异步操作,例如调用后端 API 请求数据,在处理完异步操作后再提交 Mutation。
- 规范:Actions 不直接修改 state,而是通过提交 Mutations 来改变 state。
- 调用方式:通过 dispatch 方法触发 Actions 的调用。
-
区别总结:
- 同步 vs 异步:Mutation 是同步操作,而 Action 是异步操作。
- 纯函数 vs 异步操作:Mutation 是纯函数,而 Action 可以包含各种异步操作。
- 直接修改 vs 间接修改:Mutation 直接修改状态,而 Action 通过提交 Mutation 间接修改状态。
- 调用方式:Mutation 通过 commit 触发,Action 通过 dispatch 触发。
在 Vuex 应用中,通常建议使用 Actions 来处理异步逻辑和业务逻辑,而通过 Mutation 来修改状态。
axios
Axios 是一个基于 Promise 的 HTTP 客户端,可以在浏览器和 Node.js 中发送 HTTP 请求。它支持处理请求和响应数据的转换以及拦截请求和响应等功能。
使用 Axios 发送请求。例如,发送一个 GET 请求:
axios.get('https://api.example.com/data')
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
在上面的例子中,使用 axios.get() 发送一个 GET 请求到指定的 URL,然后根据返回的 Promise 对象进行处理。可以通过 .then() 处理成功的响应结果,通过 .catch() 处理请求失败的情况。
除了 GET 请求,Axios也支持其他HTTP请求方法,如 POST、PUT、DELETE等,使用方式类似。同时,Axios也支持设置请求头、请求拦截器、响应拦截器等功能,以满足各种需求。
Promise
Promise 对象是 JavaScript 提供的用于处理异步操作的一种方式,它表示一个异步操作的最终完成(或失败),并返回相应的结果值。
-
Promise 的原理:
- 状态:Promise 对象有三种状态:
Pending(进行中)
、Fulfilled(已成功)
和Rejected(已失败)
。 - 处理过程:Promise 实例被创建时处于
Pending
状态,表示异步操作尚未完成。当操作成功完成时,Promise进入Fulfilled
状态,返回成功的结果;当操作失败时,Promise 进入Rejected
状态,返回失败的原因。 - Promise 的状态改变:
Pending
:初始状态,可以改变为 Fulfilled 或 Rejected。
Fulfilled
:表示操作成功完成,不可再变为其他状态。
Rejected
:表示操作失败,不可再变为其他状态。
- 状态:Promise 对象有三种状态:
- 可以手动修改 Promise 的状态吗:
JavaScript 中的 Promise 对象状态是自动管理的,一旦状态发生变化,就无法手动修改。Promise 的状态改变是由异步操作结果决定的,无法直接干预或修改其状态,这是为了保证异步操作的稳定性和准确性。
Hash模式和History模式
History 模式
在 History 模式下,Vue Router 通过使用 HTML5 History API 来管理路由,不会在 URL 中使用哈希(#)作为路由的标记。相反,它依赖于浏览器的 History API 来管理 URL 的变化。
使用 History 模式需要后端服务器的配合。当用户在浏览器中直接访问页面时,或者刷新页面时,后端服务器需要配置,以确保返回对应的前端路由页面。这是因为在 History 模式下,前端的路由和后端的路由是分离的,后端需要将所有路由请求都重定向到前端的入口页面。
服务器需要进行相应的配置,以确保在刷新页面或直接访问某个子路由时,仍能正确返回前端路由对应的页面。
示例 URL:https://example.com/my-routeHash 模式
在 Vue Router 中,Hash 模式是一种简单且常见的路由模式,它使用 URL 中的哈希(#)来管理路由。当 URL 中的哈希值发生变化时,Vue Router 将根据哈希值来匹配对应的路由。
使用 hash 模式时,URL 中会有一个 # 符号,后面跟着路由路径。
通过监听 hashchange 事件来改变 URL 中的哈希值,实现前端路由跳转。不需要服务器进行特殊配置,因为哈希部分的变化不会发送到服务器。
示例 URL:https://example.com/#/my-routeHistory 模式 与 Hash 模式 的区别
History 模式的 URL 更美观和干净,更类似传统的 URL 结构。
Hash 模式的 URL 兼容性好,不需要特殊的服务器配置,可以在几乎所有的环境中使用。
在使用 History 模式时,需要确保服务器端配置正确,以便在刷新页面或直接访问子路由时,能正确返回对应的页面。而 Hash 模式不需要这样的配置。
总之,History 模式的 URL 可能会更符合用户的习惯,但需要对服务器进行配置。Hash 模式则更简单易用,但 URL 中会有一个 # 符号。
import VueRouter from 'vue-router';
import Hello from "../components/Hello.vue"
import Vue from "vue";
Vue.use(VueRouter)
const router = new VueRouter({
mode: 'history',//或hash
base:'/app2/',
routes:[
{
path: '/hello',
name: 'hello',
component: Hello
},
],
})
export default router;
diff算法
diff算法就是进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方,最后用patch记录的消息去局部更新Dom。diff的过程就是调用名为patch的函数,比较新旧节点,一边比较一边给真实的DOM打补丁
- diff算法的特点
比较只会在同层级进行, 不会跨层级比较,在diff比较的过程中,循环从两边向中间比较。diff 算法的在很多场景下都有应用,在 vue 中,作用于虚拟 dom 渲染成真实 dom 的新旧 VNode 节点比较 - diff算法的步骤:
- 用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文 档当中
- 当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较(diff),记录两棵树差异
- 把第二棵树所记录的差异应用到第一棵树所构建的真正的DOM树上(patch),视图就更新了
- 比较方式
diff整体策略为:深度优先,同层比较;
比较只会在同层级进行, 不会跨层级比较,比较的过程中,循环从两边向中间收拢 - 原理分析
当数据发生改变时,set方法会调用Dep.notify通知所有订阅者Watcher,订阅者就会调用patch给真实的DOM打补丁,更新相应的视图
虚拟Dom
虚拟DOM的概念是通过状态生成一个虚拟节点树,然后使用虚拟节点树进行渲染。在渲染之前,会使用新生成的虚拟节点和上一次生成的虚拟节点进行对比,只渲染不同的部分
-
vue中的虚拟DOM
vue中状态变化时,只能通知到组件,组件内部的变化需要通过虚拟DOM去进行比对与渲染。我们使用模板来描述状态与DOM之间的映射关系。vue通过编译将模板转换成渲染函数,执行渲染函数就可以得到一个虚拟节点树,使用虚拟节点数就可以渲染页面
虚拟DOM在vue中主要提供与真实节点对应的虚拟节点vnode,然后需要将vnode和oldVnode进行比对,然后更新视图,对比两个虚拟节点的算法是patch(diff的一部分)算法
浏览器的代理、缓存和跨域问题
-
浏览器缓存:
浏览器缓存是指浏览器在本地存储已请求过的资源(如网页、图片、样式表等),以便在之后的访问中能够更快地获取这些资源而不需要重新下载。浏览器缓存分为两种:
强制缓存:浏览器直接从本地缓存中获取资源,不发起请求到服务器,通过设置响应头中的 Cache-Control 和 Expires 实现。
协商缓存:浏览器发起请求到服务器,经过协商后确定是否直接从缓存中获取资源,通过设置响应头中的 Last-Modified 和 ETag 实现。
-
跨域问题:
跨域是指浏览器出于安全考虑限制了不同域下的页面之间的交互。跨域包括以下情况:
不同域名:例如 http://example.com 和 http://test.com。
不同子域:例如 http://sub1.example.com 和 http://sub2.example.com。
不同端口:例如 http://example.com:8080 和 http://example.com:9090。- 跨域解决方案:
- JSONP:通过动态创建 script 标签实现跨域请求。
- CORS(跨域资源共享):在服务端设置相应的响应头,允许跨域请求。
- 代理:通过同源策略的限制,通过自己的服务器来转发请求。
- iframe:通过 iframe 的跨域特性实现数据的传递。
- 跨域资源共享(XHR2):以 XMLHttpRequest 对象为基础的原生支持跨域请求的技术。
- 跨域解决方案:
-
浏览器缓存和跨域问题关联:
跨域请求会受到同源策略的限制,使得浏览器在进行跨域请求时会受到缓存控制的影响。
如果跨域请求是可缓存的,则浏览器会根据响应头中的缓存信息来确定是否将响应缓存下来,从而影响后续的请求。
-
浏览器的代理问题
代理服务器:代理服务器是位于客户端和目标服务器之间的服务器,作为中间人来转发请求和响应,隐藏真实的客户端 IP 地址。
代理类型:
正向代理:代理服务器代表客户端向目标服务器发送请求。
反向代理:代理服务器代表目标服务器接收客户端的请求。作用:
隐私保护:代理可以隐藏客户端真实的 IP 地址,提高个人隐私保护。
访问控制:可以通过代理服务器控制访问权限,实现访问控制策略。
网络性能:通过代理服务器缓存网页内容,提高页面加载速度。
访问限制:某些网络可能会对特定 IP 地址或国家限制访问,代理可以绕过这种限制。
- 使用场景:
访问受限资源:访问需要特定 IP 或地区才能访问的资源。
加速访问:通过代理服务器缓存常用页面或资源,加快访问速度。
突破封锁:在某些国家或网络环境下,访问受限的网站或服务。
- 风险:
安全性:公共代理可能存在安全风险,包括泄漏用户信息和篡改请求响应。
稳定性:代理服务可能不稳定,导致访问速度变慢或无法正常访问目标网站。
隐私:使用不受信任的代理服务可能暴露个人隐私。
前端模式(前端九种设计模式)
1. 外观模式(Facade Pattern)
它提供了一个简单的接口,用于访问复杂的系统或子系统。通过外观模式,客户端可以通过一个简单的接口来访问复杂的系统,而无需了解系统内部的具体实现细节。
外观模式常常被用于封装一些常用的操作,以简化代码复杂度和提高代码可维护性。
2. 代理模式(Proxy Pattern)
代理模式是一种结构型模式,它允许在不改变原始对象的情况下,通过引入一个代理对象来控制对原始对象的访问。代理对象充当原始对象的中介,客户端与代理对象交互,代理对象再将请求转发给原始对象。
代理模式在前端开发中经常被用来处理一些复杂或者耗时的操作,例如图片的懒加载、缓存等。代理对象可以在加载图片时显示占位符,当图片加载完成后再替换占位符,从而提高页面加载速度和用户体验。
另外,代理模式还可以用来实现一些权限控制的功能。例如,在用户登录后,代理对象可以检查用户的权限,只有具有相应权限的用户才能够访问某些功能或者页面。
在 JavaScript 中,代理模式通常使用 ES6 中新增的 Proxy 对象来实现。Proxy 对象允许拦截对对象的各种操作,包括读取、赋值、函数调用等。通过使用 Proxy 对象,我们可以在不改变原始对象的情况下,控制对原始对象的访问。
当我们需要为某个类或者对象添加一些额外的行为或者控制访问时,可以使用代理模式。
前端设计模式中的
3. 工厂模式(Factory Pattern)
将对象的创建和使用分离,由工厂类负责创建对象并返回。在前端开发中,可以使用工厂模式来动态创建组件。
前端中的工厂模式是一种创建对象的设计模式,它可以让我们封装创建对象的细节,我们使用工厂方法而不是直接调用 new 关键字来创建对象,使得代码更加清晰、简洁和易于维护。在前端开发中,工厂模式通常用于创建多个相似但稍有不同的对象,比如创建一系列具有相同样式和行为的按钮或者表单。
在实现工厂模式时,通常需要创建一个工厂函数(或者叫做工厂类),该函数可以接受一些参数,并根据这些参数来创建对象。例如,我们可以创建一个ButtonFactory函数,它接受一个type参数,用于指定按钮的类型,然后根据type参数创建不同类型的按钮对象。
4. 单例模式(Singleton Pattern)
保证一个类只有一个实例,并提供一个访问它的全局访问点。在前端开发中,可以使用单例模式来管理全局状态和资源。使用场景:
- 对象字面量
- 构造函数
- 模块模式
- vuex和redux
5. 策略模式(Strategy Pattern)
定义一系列的算法,将每一个算法都封装起来,并且使它们可以相互替换。在前端开发中,可以使用策略模式来动态切换组件的算法和行为。
它可以让我们在不改变对象本身的情况下,通过修改其内部的算法实现不同的行为。策略模式常常被用于实现一些复杂的业务逻辑,特别是需要根据不同的条件进行处理的情况。
6. 迭代器模式(Iterator Pattern)
提供一种方法顺序访问一个聚合对象中的各个元素,而不需要暴露该对象的内部表示。在JavaScript中,可以使用迭代器模式来操作数组或类数组对象。
在迭代器模式中,集合对象包含一个方法,用于返回一个迭代器,该迭代器可以按顺序访问该集合中的元素。迭代器提供了一种通用的接口,使得可以使用相同的方式遍历不同类型的集合对象。
在前端开发中,迭代器模式经常用于处理集合数据,例如数组、列表等。通过使用迭代器模式,可以轻松地遍历集合对象的元素,而不必担心它们的实现方式。
7. 观察者模式(Observer Pattern)
当对象间存在一对多的关系时,使用观察者模式。当被观察的对象发生变化时,其所有的观察者都会收到通知并进行相应的操作。在JavaScript中,可以使用回调函数或事件监听来实现观察者模式。
在前端开发中,观察者模式常被用来实现组件间的数据传递和事件处理。比如,当一个组件的状态发生改变时,可以通过观察者模式来通知其他组件更新自身的状态或视图。
在观察者模式中,通常会定义两种角色:
Subject(主题):它是被观察的对象,当其状态发生改变时会通知所有的观察者。
Observer(观察者):它是观察主题的对象,当主题状态发生改变时会接收到通知并进行相应的处理。
8. 中介者模式(Mediator Pattern)
通过一个中介对象来封装一系列对象之间的交互。在JavaScript中,可以使用事件调度器来实现中介者模式。
在前端开发中,中介者模式常常被用于管理复杂的用户界面或组件之间的交互,比如 GUI 组件、聊天室、游戏等等。通过引入一个中介者对象,各个组件可以向中介者对象发送消息或事件,而不需要知道消息或事件的接收者是谁。中介者对象负责接收并分发消息或事件,从而实现组件之间的解耦和统一管理。
9.访问者模式(Visitor Pattern)
是一种行为型设计模式,用于将操作与其所操作的对象分离开来。该模式的核心思想是将操作封装在一个访问者对象中,而不是分散在各个对象中。通过将操作与对象分离开来,访问者模式可以在不修改对象结构的情况下,添加新的操作。
在前端开发中,访问者模式通常用于处理DOM树上的操作。由于DOM树结构通常很深,而且节点类型不同,因此对DOM树进行一系列的操作,常常需要写很多代码。而访问者模式可以将这些操作抽象出来,封装到访问者对象中,从而简化了代码量。
在访问者模式中,有两种角色:访问者(Visitor)和被访问者(Element)。被访问者是一组对象,它们具有不同的接口,用于接受访问者的访问。访问者则是一组对象的操作,用于处理被访问者。访问者通常会遍历整个被访问者的结构,并对每个节点进行操作。
flex布局
Flex布局又称弹性布局,它使用flexbox使得容器有了弹性,更加适应各种设备的不同宽度,而不必依赖于传统的块状布局和浮动定位。它是CSS3中新增的规范,目前主流浏览器均已支持。
分布式存储
分布式存储是一种去中心化存储,通过资源虚拟化、负载均衡、跨节点保护等技术,把多台存储设备的资源进行整合处理,整合成一个虚拟的存储设备,统一对外提供存储服务。在数据存储时,会均衡的把数据分散存储在每台底层存储设备上,最后达到数据分布存储的目的。
Vue如何监听数据
watch监听
你可以为一个特定的数据字段添加一个watcher函数,当该字段的值改变时会自动调用此函数。示例代码如下所示:
data() {
return {
message: 'Hello Vue!'
}
},
watch: {
// 监听message字段的变化
message(newValue, oldValue) {
console.log('Message changed from', oldValue, 'to', newValue);
}
}
上面的代码将在控制台输出每次message字段的新值和旧值。
计算属性(computed property)
你也可以创建一个计算属性来根据其他数据字段的值进行计算并返回结果。示例代码如下所示:
data() {
return {
firstName: '',
lastName: ''
};
},
computed: {
fullName() {
if (this.firstName && this.lastName) {
return `${this.firstName} ${this.lastName}`;
} else {
return '';
}
}
}
JS异步怎么实现?
回调函数、事件监听、发布/订阅、Promise对象、async和await函数
XSS攻击
xss攻击是跨站脚本攻击,例如在表单中提交含有可执行的javascript的内容文本,如果服务器端没有过滤或转义这些脚本,而这些脚本由通过内容的形式发布到了页面上,这个时候如果有其他用户访问这个网页,那么浏览器就会执行这些脚本,从而被攻击,从而获取用户的cookie等信息。
解决:
1、对于敏感的cookie信息,使用HttpOnly,使document对象中找不到cookie。
httpOnly 是一个常见的 Cookie 属性,用于增加对于跨站点脚本攻击(XSS)的防护。将 Cookie 的 httpOnly 属性设置为 true 会限制浏览器端 JavaScript 对该 Cookie 的访问,只允许在 HTTP 请求中自动发送 Cookie,而禁止通过 JavaScript 来读取或修改该 Cookie。
2、对于用户输入的信息要进行转义。
http、https加密
http是明文传输,https是密文传输,在http的基础上添加 SSL/TLS协议进行加密保护,需要提供SSL证书,在证书下使用对称加密。
SSL
全称为Secure Sockets Layer
,即安全套接层。SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。
CSS重设
一种避免浏览器兼容性问题的方法,CSS 重设也叫CSS复位、默认CSS、CSS重置等。CSS重设就是由于各种浏览器解释CSS样式的初始值有所不同,导致设计师在没有定义某个CSS属性时,不同的浏览器会按照自己的默认值来为没有定义的样式赋值,所以我们要先定义好一些CSS样式,来让所有浏览器都按照同样的规则解释CSS,这样就能避免发生这种问题。
es6新增特性
1.let和const关键字
2.解构赋值
3.箭头函数
4.模板字符串:使用反引号``代替双引号创建字符串
5.标签模板
6.扩展运算符
7.新增了一些字符串和数组方法
8.Symbol
9.迭代器(Iterator)
10.生成器
11.Promise承诺
1.let和const关键字
微任务和宏任务
微任务(microtask) 微任务是指在当前任务执行结束后立即执行的任务,它可以看作是在当前任务的“尾巴”添加的任务。
宏任务(macrotask) 宏任务是指需要排队等待 JavaScript 引擎空闲时才能执行的任务。常见的宏任务包括 setTimeout、setInterval、I/O 操作、DOM 事件等。常见的微任务包括 Promise 回调和 process.nextTick。
JavaScript 引擎会先执行当前任务中的所有微任务,然后再执行宏任务队列中的第一个任务。
要区分微任务和宏任务,是因为微任务和宏任务的执行顺序不同,这对 Web 开发中一些异步操作的实现有着重要的影响。 在 JavaScript 中,微任务会优先于宏任务执行。这意味着在当前任务执行结束后,所有微任务都会被立即执行,而宏任务只有在所有微任务执行完毕后才会执行。这种执行顺序保证了微任务的优先级,可以避免一些问题的出现
GET与POST
相同点
GET 请求和 POST 请求底层都是基于 TCP/IP 协议实现的,使用二者中的任意一个,都可以实现客户端和服务器端的双向交互。
不同点
- get请求一般是去取获取数据(其实也可以提交,但常见的是获取数据);post请求一般是去提交数据。
- get因为参数会放在url中,所以隐私性,安全性较差,请求的数据长度是有限制的,不同的浏览器和服务器不同,一般限制在 2~8K 之间,更加常见的是 1k 以内;post请求是没有的长度限制,请求数据是放在body中;
- get请求刷新服务器或者回退没有影响,post请求回退时会重新提交数据请求。
- get请求可以被缓存,post请求不会被缓存。
- get请求会被保存在浏览器历史记录当中,post不会。get请求可以被收藏为书签,因为参数就是url中,但post不能。它的参数不在url中。
- get请求只能进行url编码(appliacation-x-www-form-urlencoded),post请求支持多种(multipart/form-data等)。