目录
1 问了Vue 和react 的区别 没回答 不会 react
1.computed和wacth的区别
2.使用过哪种路由模式 hash和history的区别
2.2、hash模式
2.3、history 模式
3.style标签的scoped属性的原理
scoped 穿透(深度作用选择器)
4.常用的vue指令 说了大概十个左右
1 v-once
2 v-show
3 v-if、v-else、v-else-if
4 v-for
5 v-text和v-html
6 v-bind
7 v-on
8 v-model
9 v-pre指令
10 v-slot指令
5.vuex的问题 commit和dispatch什么情况下使用
6.vuex数据更新视图不更新 (vuex中操作数据时遇见视图不更新的情况)
6.webpack里loader和plugin是什么 分别用过哪些
webpack 的核心概念都有哪些?
7 你知道哪些优化性能的方法?
7 列举你知道的Web性能优化方法。
7 优化性能-渲染
7 优化性能-浏览器缓存机制
7 优化性能-请求优化
减少请求数量
7 优化性能-CSS
7.webPack性能优化
1 优化代码运行性能
1Code Split 2 Preload / Prefetch 3 Network Cache 4 Core - js 5 PWA
Code Split :
Preload / Prefetch 懒加载
Network Cache 第二次请求资源读取缓存
Core - js core-js 是专门用来做 ES6 以及以上 API 的 polyfill
2 提升打包速度
1HotModuleReplacement(HMR/热模块替换) 2OneOf 3 Include/Exclude 4 Cache 5 Thead
3 减少代码体积
1 Tree Shaking 2 Babel 3 Image Minimizer
8.怎么判断一个对象是否为空
9.问了一些flex布局的问题
10 htm5 新特性
11 css3 新特性
12 js闭包
13 行内元素
block块级元素
14 px rem
15 Vue 生命周期钩子
Vue2.x 和 Vue3.x 生命周期对比
16 Vue数据响应 你知道Vue的数据响应式原理是什么吗
16.2 vue数据的双向绑定原理 ,如何实现vue的双向绑定(面试题)
17 js 异步加载
Vue数据双向绑定原理
Vue2 的响应式原理:
Vue3.x响应式数据原理
Vue3.0 里为什么要用 Proxy API替代 defineProperty API?
Proxy 与 Object.defineProperty 优劣对比
Vue组件通信有哪些方式
vue中组件的data为什么是一个函数?而new Vue 实例里,data 可以直接是一个对象
vue中data的属性可以和methods中方法同名吗,为什么?
虚拟DOM中key的作用
vue开发中,数据更新,但视图不刷新
vue中对mixins的理解和使用
v-show和v-if指令的共同点和不同点
为什么避免v-if和v-for一起使用
Vue.set 改变数组和对象中的属性
vm.$set(obj, key, val) 做了什么?
keep-alive了解吗
什么情况下使用 Vuex?
Vuex和单纯的全局对象有什么区别
为什么 Vuex 的 mutation 中不能做异步操作?
做过哪些Vue的性能优化
Vue3有了解过吗?能说说跟Vue2的区别吗
速度更快
体积更小
更易维护
composition Api
Vue 3.0 所采用的 Composition Api 与 Vue 2.x使用的Options Api 有什么区别?
element-ui中遇到的问题
watch和computed都是以Vue的依赖追踪机制为基础的,它们都试图处理这样一件事情:当某一个数据(称它为依赖数据)发生变化的时候,所有依赖这个数据的“相关”数据“自动”发生变化,也就是自动调用相关的函数去实现数据的变动
watch和computed各自处理的数据关系场景不同
1.computed擅长处理的场景:一个数据受多个数据影响
2.watch擅长处理的场景:一个数据影响多个数据
3 computed支持缓存,相依赖的数据发生改变才会重新计算;watch不支持缓存,只要监听的数据变化就会触发相应操作
4 computed不支持异步,当computed内有异步操作时是无法监听数据变化的;watch支持异步操作
5 computed属性的属性值是一函数,函数返回值为属性的属性值,computed中每个属性都可以设置set与get方法。watch监听的数据必须是data中声明过或父组件传递过来的props中的数据,当数据变化时,触发监听器
watch跟computed的区别_前端开发小司机的博客-CSDN博客_watch和computed的区别
vue中 computed和watch的一些简单理解(区别)_林_xi的博客-CSDN博客
前端路由:原理篇_Palate的博客-CSDN博客_前端路由原理
使用过history模式 ,
hash 模式 url 里面永远带着 # 号,在开发当中默认使用这个模式。
hash 原理
hash 通过监听浏览器 onhashchange 事件变化,查找对应路由应用。通过改变 location.hash 改变页面路由。
history 原理
利用 html5 的history Interface 中新增的 pushState() 和 replaceState() 方法,改变页面路径。
history Interface 是浏览器历史记录栈提供的接口,可通过 back、forward、go 等,可以读取历览器历史记录栈的信息,pushState、repalceState 还可以对浏览器历史记录栈进行修改。
hash 与 history 区别对比:
vue-router实现history模式配置_注释科长的博客-CSDN博客_vue配置history模式
1. 原理
使用window.location.hash属性及窗口的onhashchange事件,可以实现监听浏览器地址hash值变化,执行加载相应的内容。
2. 理解要点
什么是hash值
hash指的是地址中#号以及后面的字符,也称为散列值。hash也称作锚点,本身是用来做页面跳转定位的。如http://localhost/index.html#abc,这里的#abc就是hash;
hash值不会发送到服务器
hash值是不会随请求发送到服务器端的,所以改变hash,不会重新加载页面;
监听 hashchange 事件
监听 window 的 hashchange 事件,当散列值改变时,可以通过 location.hash 来获取和设置hash值;
hash值变化反应到地址栏
location.hash值的变化会直接反应到浏览器地址栏;
1. 原理
history 对象保存了当前窗口访问过的所有页面网址。history 对象发生改变时,只会改变页面的路径,不会刷新页面。
每当 history 对象出现变化时,就会触发 popstate事件。
2. 理解要点
History 对象
HTML5的History API为浏览器的全局history对象增加的扩展方法。一般用来解决ajax请求无法通过回退按钮回到请求前状态的问题。History 对象保存了当前窗口访问过的所有页面网址。通过 history.length 可以得出当前窗口一共访问过几个网址。
由于安全原因,浏览器不允许脚本读取这些地址,但是允许在地址之间导航。
浏览器工具栏的“前进”和“后退”按钮,其实就是对 History 对象进行操作。
改变url方法
在 history 路由中,我们一定会使用window.history中的方法,常见的操作有:
back():后退到上一个路由;
forward():前进到下一个路由,如果有的话;
go(number):进入到任意一个路由,正数为前进,负数为后退;
pushState(obj, title, url):前进到指定的 URL,不刷新页面;
replaceState(obj, title, url):用 url 替换当前的,不刷新页面;
调用这几种方式时,都会只是修改了当前页面的 URL,不会刷新页面。如果有面试官问起这个问题“如何仅修改页面的 URL,而不发送请求”,那么答案就是这 5 种方法。但前 3 个方法只是路由历史记录的前进或者后退,无法跳转到指定的 URL。
pushState和replaceState 是HTML5 新增的history对象的方法,提供了对历史记录进行修改的功能。页面不会刷新,只是导致 History 对象发生变化,地址栏会有变化。
共同点
改变url地址,不刷新页面
监听url地址变化,加载相应内容
区别
hash会在浏览器地址后面增加#号,而history可以自定义地址。
hash路由不需要服务端的支持,history需要服务端支持,因为hash值不会发给后端,而history模式修改URL地址后,再进行刷新会使用该地址发送请求。
Vue style 属性 scoped 原理详解_薛定谔的panda的博客-CSDN博客_scoped的原理
当 style 标签有 scoped 属性时,它的 CSS 只作用于当前组件中的元素。通过该属性,可以使组件之间的样式互不污染,实现样式的模块化。
通过给 dom 增加一个动态属性,然后 css 选择器也额外添加对应的属性来选择该 dom ,达到该样式只作用于含有该属性的 dom,实现组件样式的模块化。
scoped 原理
主要通过使用 PostCSS 来实现以下转换:
通过给 dom 增加一个动态属性,然后 css 选择器也额外添加对应的属性来选择该 dom ,达到该样式只作用于含有该属性的 dom,实现组件样式的模块化。
hi
转换结果:
hi
如果你希望 scoped 样式中的一个选择器能够作用得“更深”,例如影响子组件,你可以使用 >>> 操作符:
权重等级
通用选择器(*)、子选择器(>)、相邻选择器(+)、同胞选择器(~)、权重值为0
相同权重下:内嵌样式 > 内部样式表 > 外联样式表
我们可以通过改变权重修改样式,scoped 实质就是添加了属性选择器增加了10的权重,我们只要超过他就可以了。
如 vue-loader 提供的 >>> 实质就是为第三方组件增加了外层属性的类,并且该类也带有属性选择器,相当于增加了20的权重。
那么我们可以为组件增加一个命名空间,防止变量污染,然后在当前命名空间下添加选择器增加权重达到修改样式的目的。
只会执行一次渲染,当数据发生改变时,不会再变化
v-show接受一个表达式或一个布尔值。相当于给元素添加一个display
属性
v-if和v-show有同样的效果,不同在于v-if是重新渲染,而v-show使用display属性来控制显示隐藏。频繁切换的话使用v-show减少渲染带来的开销。
说明一下:v-if可以单独使用,而v-else-if,v-else必须与v-if组合使用
v-if、v-else-if都是接受一个条件或布尔值,v-else不需要参数。比较简单,看看案例:
v-for可用来遍历数组、对象、字符串。
只要连续生成一组结构相同,但是内容不同的HTML元素时,都用v-for批量生成
v-text
是渲染字符串,会覆盖原先的字符串
v-html
是渲染为html。{{}}
双大括号和v-text
都是输出为文本。那如果想输出为html。使用v-html
,如下例子
是用可以将标签内的属性值解析成js代码,在标签的属性中使用v-bind,双引号里的内容会被当作js解析(只能解析变量或三元表达式),如下:
如果给属性值设置为一个变量,那么可以使用v-bind
可以缩写为:<属性>="<变量>"
v-on
用于事件绑定
语法: v-on:<事件类型>="<函数名>"
简写:@<事件类型>="<函数名>"
数据双向绑定指令,限制在 、
、components中使用
语法: v-model="<变量名>"
适用: /
作用:在表单控件或者组件上创建双向绑定。
作用:跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
注意:不需要表达式。
适用:只能用于
作用:提供具名插槽或需要接收 prop 的插槽。
缩写:#
vuex 中的 dispatch 和 commit 的使用_雪爪鸿泥的博客-CSDN博客_vuex中的dispatch
dispatch 异步操作 this.$store.dispatch(‘actions的方法’,arg); 调用 actions 里面的方法。
commit 同步操作 this.$store.commit(‘mutations的方法’,arg);调用 mutations 里面的方法。
dispatch:含有异步操作,例如向后台提交数据,写法: this.$store.dispatch(‘action方法名’,值)
commit:同步操作,写法:this.$store.commit(‘mutations方法名’,值)
使用情况:
- dispatch:提交到 actions,action方法里可以提交mutation方法,可以包含异步操作,如向后台发送网络请求登录
- commit:提交到 mutations,mutation方法只能是同步操作,可用于登录成功后读取用户信息保存到cookie
this.$store.commit('aMutation', payload);
this.$store.dispatch('aAction', payload);
Vuex的5个属性
state:单一状态树,用一个对象就包含了全部的应用层级状态。
getters:就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
mutations:每个mutation都有一个字符串的事件类型 (type) 和一个回调函数 (handler)。
action:action 类似于mutation,不同在于:action 提交的是mutation,而不是直接变更状态;action可以包含任意异步操作。
modules:模块化vuex,每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。
Vuex 使用流程:
下载 vuex
在 src 下创建 store 以及 index.js
引入 vue 和 vuex, 使用 vuex ,导出实例对象
在 main.js 中引入,在.vue 文件中使用
vuex 直接修改state 和commit ,dispatch 修改state 的区别_yuange11111的博客-CSDN博客_state.dispatch
vuex中store.commit和store.dispatch的用法及区别_天生喜欢的博客-CSDN博客_store.commit
原因是:是vuex不能监听到数组的长度变化。
Vue2 Object.defineProperty的本身的机制问题
解决办法就很简单了,在每次修改数据之前,先将数据重置。
state: {
routeViews: [], //路由存储数组
},
mutations: {
routeViews(state, obj){
state.routeViews = null //先把数组置空,不然视图不更新
state.routeViews = obj
}
},
参考答案:
loader
加载器,主要用于代码转换,比如 JS 代码降级,CSS 预编译、模块化等
plugin
插件,webpack 打包流程中每个环节都提供了钩子函数,可以利用这些钩子函数参与到打包生命周期中,更改或增加 webpack 的某些功能,比如生成页面和 css 文件、压缩打包结果等
module
模块。webpack 将所有依赖均视为模块,无论是 js、css、html、图片,统统都是模块
entry
入口。打包过程中的概念,webpack 以一个或多个文件作为入口点,分析整个依赖关系。
chunk
打包过程中的概念,一个 chunk 是一个相对独立的打包过程,以一个或多个文件为入口,分析整个依赖关系,最终完成打包合并
bundle
webpack 打包结果
tree shaking
树摇优化。在打包结果中,去掉没有用到的代码。
HMR
热更新。是指在运行期间,遇到代码更改后,无须重启整个项目,只更新变动的那一部分代码。
dev server
开发服务器。在开发环境中搭建的临时服务器,用于承载对打包结果的访问
(1)减少HTTP请求次数,控制CSS Sprite、JavaScript与CSS源码、图片的大小,使用网页Gzip、CDN托管、data缓存、图片服务器
(2)通过前端模板 JavaScript和数据,减少由于HTML标签导致的带宽浪费,在前端用变量保存Ajax请求结果,每次操作本地变量时,不用请求,减少请求次数。
(3)用 innerhTML代替DOM操作,减少DOM操作次数,优化 JavaScript性能。
(4)当需要设置的样式很多时,设置 className而不是直接操作 Style。
(5)少用全局变量,缓存DOM节点查找的结果,减少I/O读取操作
(6)避免使用CSS表达式,它又称动态属性,
(7)预加载图片,将样式表放在顶部,将脚本放在底部,加上时间戳。
(8)避免在页面的主体布局中使用表,表要在其中的内容完全下载之后才会显示出来,显示的速度比DIV+CSS布局慢。
(1)压缩源码和图片( JavaScript采用混淆压缩,CSS进行普通压缩,JPG图片根据具体质量压缩为50%~70%,把PNG图片从24色压缩成8色以去掉一些PNG格式信息等)。
(2)选择合适的图片格式(颜色数多用JPG格式,而很少使用PNG格式,如果能通过服务器端判断浏览器支持WebP就用WebP或SVG格式)。
(3)合并静态资源(减少HTTP请求)
(4)把多个CSS合并为一个CSS,把图片组合成雪碧图。
(5)开启服务器端的Gzip压缩(对文本资源非常有效)。
(6)使用CDN(对公开库共享缓存)。
(7)延长静态资源缓存时间。
(8)把CSS放在页面头部把 JavaScript代码放在页面底部(这样避免阻塞页面渲染而使页面出现长时间的空白)
重绘
重绘指的是不影响界面布局的操作,比如更改颜色,那么根据上面的渲染讲解我们知道,重绘之后我们只需要在重复进行一下样式计算,就可以直接渲染了,对浏览器渲染的影响相对较小
重排
重排指的是影响界面布局的操作,比如改变宽高,隐藏节点等。对于重排就不是一个重新计算样式那么简单了,因为改变了布局,根据上面的渲染流程来看涉及到的阶段有样式计算,布局树重新生成,分层树重新生成,所以重排对浏览器的渲染影响是比较高的
避免方法
js 尽量减少对样式的操作,能用 css 完成的就用 css
对 dom 操作尽量少,能用 createDocumentFragment 的地方尽量用
如果必须要用 js 操作样式,能合并尽量合并不要分多次操作
resize 事件 最好加上防抖,能尽量少触发就少触发
加载图片的时候,提前写好宽高
从前端性能优化引申出来的5道经典面试题(值得收藏)_傲娇的koala的博客-CSDN博客
缓存方式
我们经常说的浏览器缓存有两种,一种是强制缓存,一种是协商缓存,因为下面有具体实现讲解,所以这里就说一下概念
协商缓存
协商缓存意思是文件已经被缓存了,但是否从缓存中读取是需要和服务器进行协商,具体如何协商要看请求头/响应头的字段设置,下面会说到。需要注意的是协商缓存还是发了请求的
强制缓存
强制缓存就是文件直接从缓存中获取,不需要发送请求
缓存在哪里
form memory cache
这个是缓存在内存里面,优点是快速,但是具有时效性,当关闭 tab 时候缓存就会失效。
from dist cache
这个是缓存在磁盘里面,虽然慢但是还是比请求快,优点是缓存可以一直被保留,即使关闭 tab 页,也会一直存在
将小图片打包成base64
利用雪碧图融合多个小图片
利用缓存
减少请求时间
(1)正确使用 display属性, display属性会影响页面的渲染,因此要注意以下几方面。
display:inline后不应该再使用 width、 height、 margin、 padding和float 。
display:inline- block后不应该再使用 float。
display:block后不应该再使用 vertical-align。
display:table-*后不应该再使用 margin或者float。
(2)不滥用 float。
(3)不声明过多的font-size。
(4)当值为0时不需要单位。
(5)标准化各种浏览器前缀,并注意以下几方面。
浏览器无前缀应放在最后。
CSS动画只用( -webkit-无前缀)两种即可。
其他前缀包括 -webkit-、-moz-、-ms-、无前缀( Opera浏览器改用 blink内核,所以-0-被淘汰)
(6)避免让选择符看起来像是正则表达式。高级选择器不容易读懂,执行时间也长。
(7)尽量使用id、 class选择器设置样式(避免使用 style属性设置行内样式)
(8)尽量使用CSS3动画。
(9)减少重绘和回流。
所以我们需要将打包生成的文件进行代码分割,生成多个 js 文件,渲染哪个页面就只加载某个 js 文件,这样加载的资源就少,速度就更快。
Preload
:告诉浏览器立即加载资源。
Prefetch
:告诉浏览器在空闲时才开始加载资源。
我们前面已经做了代码分割,同时会使用 import 动态导入语法来进行代码按需加载(我们也叫懒加载,比如路由懒加载就是这样实现的)。
但是这样的话就会有一个问题, 因为前后输出的文件名是一样的,都叫 main.js,一旦将来发布新版本,因为文件名没有变化导致浏览器会直接读取缓存,不会加载新资源,项目也就没法更新了。
所以我们从文件名入手,确保更新前后文件名不一样,这样就可以做缓存了。
core-js
是专门用来做 ES6 以及以上 API 的 polyfill
polyfill
翻译过来叫做垫片/补丁。就是用社区上提供的一段代码,让我们在不兼容某些新特性的浏览器上,使用该新特性
js 代码仍然存在兼容性问题,一旦遇到低版本浏览器会直接报错。所以我们想要将 js 兼容性问题彻底解决
PWA 提供离线体验 (不谈)
渐进式网络应用程序(progressive web application - PWA):是一种可以提供类似于 native app(原生应用程序) 体验的 Web App 的技术。
其中最重要的是,在 离线(offline) 时应用程序能够继续运行功能。
HotModuleReplacement(HMR/热模块替换):在程序运行中,替换、添加或删除模块,而无需重新加载整个页面。
OneOf :打包时每个文件都会经过所有 loader 处理,虽然因为 test 正则原因实际没有处理上,但是都要过一遍。比较慢。
Include/Exclude:开发时我们需要使用第三方的库或插件,所有文件都下载到 node_modules 中了。而这些文件是不需要编译可以直接使用的。所以我们在对 js 文件处理时,要排除 node_modules 下面的文件。
Cache: 开启缓存
缓存目录 每次打包时 js 文件都要经过 Eslint 检查 和 Babel 编译,速度比较慢。
我们可以缓存之前的 Eslint 检查 和 Babel 编译结果,这样第二次打包时速度就会更快了。、
Thead:
而对 js 文件处理主要就是 eslint 、babel、Terser 三个工具,所以我们要提升它们的运行速度。
我们可以开启多进程同时处理 js 文件,这样速度就比之前的单进程打包更快了。
1如何获取 CPU 的核数,因为每个电脑都不一样。
// nodejs核心模块,直接使用
const os = require("os");
// cpu核数
const threads = os.cpus().length;
2 下载包
npm i thread-loader -D
3 使用
use: [
{
loader: "thread-loader", // 开启多进程
options: {
workers: threads, // 数量
},
},
1 Tree Shaking
开发时我们定义了一些工具函数库,或者引用第三方工具函数库或组件库。
如果没有特殊处理的话我们打包时会引入整个库,但是实际上可能我们可能只用上极小部分的功能。这样将整个库都打包进来,体积就太大了。
Webpack 已经默认开启了这个功能,无需其他配置
2 Babel
Babel 为编译的每个文件都插入了辅助代码,使代码体积过大!
Babel 对一些公共方法使用了非常小的辅助代码,比如 _extend
。默认情况下会被添加到每一个需要它的文件中。
你可以将这些辅助代码作为一个独立模块,来避免重复引入
3 Image Minimizer压缩图片的插件
开发如果项目中引用了较多图片,那么图片体积会比较大,将来请求速度比较慢。
我们可以对图片进行压缩,减少图片体积。
注意:如果项目中图片都是在线链接,那么就不需要了。本地项目静态图片才需要进行压缩。
image-minimizer-webpack-plugin: 用来压缩图片的插件
1.将json对象转化为json字符串,再判断该字符串是否为"{}"
2.for in 循环判断 若不为空,可遍历,返回false 空 返回true
3.jquery的isEmptyObject方法
4 Object.keys()方法,返回对象的属性名组成的一个数组,若长度为0,则为空对象(ES6的写法) console.log(Object.keys(obj).length==0);//返回true
5 Object.getOwnPropertyNames方法获取对象的属性名,存到数组中,若长度为0,则为空对象 console.log(Object.getOwnPropertyNames(obj).length==0);//返回true
1》主轴上对齐方式:
justify-content:flex-start | flex-end | center | space-between | space-around;
2》交叉轴上对齐方式
align-items:flex-start | flex-end | center | baseline | stretch;
3》项目排列方向
flex-direction:row | row-reverse | column | column-reverse;
4》换行方式
flex-wrap:nowrap(不换行) | wrap(向下换) | wrap-reverse(向上换);
5》flex-flow
flex-direction和flex-wrap的简写
6》多根轴线的对齐方式
align-content:flex-start | flex-end | center | space-between | space-around | stretch;
6》多根轴线的对齐方式
2)Flex布局子元素属性
HTML5的新特性_龟苓膏先生的博客-CSDN博客_html5新特性
一、语义化标签
标签的语义化,就是根据内容结构,选择合适的标签编写相应的代码内容。正确的标签做正确的事。语义化标签的好处:1.方便开发人员的代码阅读和后期维护。2.提高用户体验(img 的 alt,title)。3.有利于seo搜索引擎优化。4.便于网络爬虫解析文档 。
二、新增Input表单的类型、和属性
1.类型
tel、number、date、time、week、month、url、email、color、rang
2.属性
required: ture 必填属性
placeholder:'提示文本'
autofocus 自动聚焦
pattern 正则验证内容
multiple 可选多个值()上传文件
width,height 宽度高度 type=image
autocomplete on/off 是否展示历史输入
min/max 设置元素最大值最小值
三、audio、video音频和视频
HTML5 提供了播放音频、视频文件的标准,即使用
四、Canvas绘图
你可以通过多种方法使用 canvas 绘制路径,盒、圆、字符以及添加图像。
五、SVG绘图
六、地理定位
七、拖拽API
拖放是一种常见的特性,即抓取对象以后拖到另一个位置。
在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放
八、WebStorage
使用HTML5可以在本地存储用户的浏览数据。
LocalStorage和SessionStorage都是HTML5提出的存储方案。大小一般为5MB,可以存储更多信息。均受到同源策略的限制
九、WebWorker
当在 HTML 页面中执行脚本时,页面的状态是不可响应的,直到脚本已完成。
web worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能。您可以继续做任何愿意做的事情:点击、选取内容等等,而此时 web worker 在后台运行。
十、WebSocket
WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。
关于CSS3的新特性(面试经典)_我,小李!的博客-CSDN博客_css3新特性 面试
1.过渡属性
transition: 要改变的属性,花费时间,效果曲线(默认ease),延迟时间(默认0)
2.动画属性
animation:动画名称,一个周期花费时间,运动曲线(默认ease),动画延迟(默认0),播放次数(默认1),是否反向播放动画(默认normal),是否暂停动画(默认running)
3.圆角属性:
CSS border-radius - 指定每个角
4.引入了RGBA 颜色函数
5.背景色渐变 background - image: linear - gradient(red, yellow);
6.盒子阴影
box - shadow: 10px 10px 5px #888888;
7.盒子新特性 box - sizing: border - box; 算布局
8.justify - content 在容器中央对齐弹性项目
8.justify - content 在容器中央对齐弹性项目
10.transform(旋转)
11.准许文字换行 word-wrap
理解:主要是为了设计私有的方法和变量。
优点:可以避免全局变量造成污染。
缺点:闭包会常驻内存,增加内存使用量,使用不当会造成内存泄漏。
特征:(1)函数嵌套函数。(2)在函数内部可以引用外部的参数和变量。(3)参数和变量不会以垃圾回收机制回收。
span、img、a、lable、input、abbr(缩写)、em(强调)、big、cite(引用)、i(斜体)、q(短引用)、textarea、select、small、sub、sup,strong、u(下划线)、button(默认display:inline-block))
div、p、h1…h6、ol、ul、dl、table、address、blockquote、form
inline-block内联块元素
img、input
组件的生命周期共分为三个阶段:挂载阶段、更新阶段、销毁阶段。
每个阶段对应的钩子函数分别为:
- 挂载阶段:beforeCreate、created、beforeMount、mounted
- 更新阶段:beforeUpdate、updated
- 销毁阶段:beforeDestroy、destroyed
使用
组件会将数据保留在内存中,比如我们不想每次看到一个页面都重新加载数据,就可以使用
组件解决。
Vue2
1. beforeCreate() 创建前
2. created()创建后
3. beforeMount() 挂载前
4. mounted()挂载完成
5. beforeUpdate() 更新前
6. updated() 更新后
7. beforeDestroy() 销毁前
8. destroyed() 销毁完成
Vue3
Vue3生命周期钩子
setup() : 开始创建组件之前,在 beforeCreate 和 created 之前执行,创建的是 data 和 method
onBeforeMount() : 组件挂载到节点上之前执行的函数;
onMounted() : 组件挂载完成后执行的函数;
onBeforeUpdate(): 组件更新之前执行的函数;
onUpdated(): 组件更新完成之后执行的函数;
onBeforeUnmount(): 组件卸载之前执行的函数;
onUnmounted(): 组件卸载完成后执行的函数;
onActivated(): 被包含在
onDeactivated(): 比如从 A 组件,切换到 B 组件,A 组件消失时执行;
onErrorCaptured(): 当捕获一个来自子孙组件的异常时激活钩子函数。
Vue3 生命周期钩子函数_叶子_o的博客-CSDN博客_vue3钩子函数
父子组件钩子函数在三个阶段的代码执行顺序
挂载:父亲created> 子created > 子mounted> 父亲mounted>
更新:父亲beforeUpdate > 子beforeUpdated > 子updated > 父亲updated
销毁:父亲beforeDestroy> 子beforeDestroy > 子destroyed> 父destroyed
一起来聊聊Vue3的这“一生(生命周期)”_李公子丶的博客-CSDN博客_vue3生命周期图
vue的数据响应式就是当数据发生变化,通知改变的代码。数据响应式原理的核心就是采用了数据劫持结合发布者-订阅者模式的方式来实现数据的响应式,通过Object.defineProperty()对数据进行拦截,把这些属性全部转换成getter/setter,get()方法可以读取数据、收集依赖,set()方法可以改写数据,在数据变动时会对数据进行比较,如果数据发生了变化,会发布消息通知订阅者,触发监听回调,更新视图。
面试题53:vue数据的双向绑定原理(如何实现vue的双向绑定)_The..Fuir的博客-CSDN博客_vue双向绑定的原理面试题
采用“数据劫持”结合“发布者-订阅者”模式的方式,通过“Object.defineProperty()”方法来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调
概念:双向绑定是vue的一个核心功能,所谓双向绑定就是当视图发生改变的时候传递给VM(ViewModel ),让数据得到更新,当数据发生改变的时候传给VM(ViewModel ),使得视图发生变化
利用 Object.defineProperty 自己实现双向数据绑定
//利用 Object.defineProperty 自己实现双向数据绑定
//1.async 只能加载外部脚本
②defer 异步加载,但要等到dom文档全部解析完才会被执行。只有IE能用内部外部js均可使用
//2.defer 只能IE使用,文档解析完成以后才会去执行
1.但要等dom文档全部解析完(dom树生成)才会被执行。
2.只有IE能用;
3 按需求加载,考虑浏览器兼容 script .on ready state change 函数
function loadScript(url,callback){
var script = document.createElement("script");
if(script.readyState){ IE浏览器兼容
script.onreadystatechange = function(){
if(script.readyState == "complete" || script.readState == "loaded"){
callback()
}
}
}else{ 大部分浏览器兼容
script.onload = function(){
callback()
}
}
script.src = url;
document.head.appendChild(script)
}
loadScript("08.js",function(){
test()
})
//外部js
function test(){
console.log("hello world")
}
document三个状态
①loading 加载中状态,dom树正在绘制中
②interactive 活跃状态,dom树绘制完成
③complete 完成状态(老版本的浏览器可能是loaded),dom树绘制完成并且所有的资源下载完成
实现mvvm的数据双向绑定,是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来给各个属性添加setter,getter并劫持监听,在数据变动时发布消息给订阅者,触发相应的监听回调。就必须要实现以下几点:
1、实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
什么是响应式,也即是说,数据发生改变的时候,视图会重新渲染,匹配更新为最新的值。
Object.defineProperty 为对象中的每一个属性,设置 get 和 set 方法,每个声明的属性,都会有一个 专属的依赖收集器 subs,当页面使用到 某个属性时,触发 ObjectdefineProperty - get函数,页面的 watcher 就会被 放到 属性的依赖收集器 subs 中,在 数据变化时,通知更新;
当数据改变的时候,会触发Object.defineProperty - set函数,数据会遍历自己的 依赖收集器 subs,逐个通知 watcher,视图开始更新;
Vue3.x改用Proxy替代Object.defineProperty。
因为Proxy可以直接监听对象和数组的变化,并且有多达13种拦截方法。并且作为新标准将受到浏览器厂商重点持续的性能优化。
Proxy只会代理对象的第一层,Vue3是怎样处理这个问题的呢?
判断当前Reflect.get的返回值是否为Object,如果是则再通过reactive方法做代理, 这样就实现了深度观测。
reactive 函数,就是利用各种集合来存储原始数据和响应式数据的映射关系,以便快速根据这种映射关系拿到对应的数据
监测数组的时候可能触发多次get/set,那么如何防止触发多次呢?我们可以判断key是否为当前被代理对象target自身属性,也可以判断旧值与新值是否相等,只有满足以上两个条件之一时,才有可能执行trigger。
Vue3 源码解析系列 - 响应式原理(reactive 篇) - 知乎
1.defineProperty API 的局限性最大原因是它只能针对单例属性做监听。
Vue2.x中的响应式实现正是基于defineProperty中的descriptor,对 data 中的属性做了遍历 + 递归,为每个属性设置了 getter、setter。这也就是为什么 Vue 只能对 data 中预定义过的属性做出响应的原因。
2.Proxy API的监听是针对一个对象的,那么对这个对象的所有操作会进入监听操作, 这就完全可以代理所有属性,将会带来很大的性能提升和更优的代码。
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
3.响应式是惰性的。
在 Vue.js 2.x 中,对于一个深层属性嵌套的对象,要劫持它内部深层次的变化,就需要递归遍历这个对象,执行 Object.defineProperty 把每一层对象数据都变成响应式的,这无疑会有很大的性能消耗。
在 Vue.js 3.0 中,使用 Proxy API 并不能监听到对象内部深层次的属性变化,因此它的处理方式是在 getter 中去递归响应式,这样的好处是真正访问到的内部属性才会变成响应式,简单的可以说是按需实现响应式,减少性能消耗。
1.Proxy 可以直接监听对象而非属性;
2.Proxy 可以直接监听数组的变化;
3.Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的;
4.Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;
5.Proxy 作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利;
6.Object.defineProperty 的优势如下:
兼容性好,支持 IE9,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平,因此 Vue 的作者才声明需要等到下个大版本( 3.0 )才能用 Proxy 重写。
1.父传子:props
父组件通过 props 向下传递数据给子组件。注:组件中的数据共有三种形式:data、props、computed
2.父传子孙:provide 和 inject
父组件定义provide方法return需要分享给子孙组件的属性,子孙组件使用 inject 选项来接收指定的我们想要添加在这个实例上的 属性;
3.子传父:通过事件形式
子组件通过 $emit()给父组件发送消息,父组件通过v-on绑定事件接收数据。
4.父子、兄弟、跨级:eventBus.js
这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来(e m i t ) 触 发 事 件 和 ( emit)触发事件和(emit)触发事件和(on)监听事件,巧妙而轻量地实现了任何组件间的通信。
6.vuex
vuex 是 vue 的状态管理器,存储的数据是响应式的。只需要把共享的值放到vuex中,其他需要的组件直接获取使用即可;
我们知道,Vue组件其实就是一个Vue实例。
JS中的实例是通过构造函数来创建的,每个构造函数可以new出很多个实例,那么每个实例都会继承原型上的方法或属性。
Vue的data数据其实是Vue原型上的属性,数据存在于内存当中。Vue为了保证每个实例上的data数据的独立性,规定了必须使用函数,而不是对象。
因为使用对象的话,每个实例(组件)上使用的data数据是相互影响的,这当然就不是我们想要的了。对象是对于内存地址的引用,直接定义个对象的话组件之间都会使用这个对象,这样会造成组件之间数据相互影响。
使用函数后,使用的是data()函数,data()函数中的this指向的是当前实例本身,就不会相互影响了。
而 new Vue 的实例,是不会被复用的,因此不存在引用对象的问题。
可以同名,methods的方法名会被data的属性覆盖;调试台也会出现报错信息,但是不影响执行;
原因:源码定义的initState函数内部执行的顺序:props>methods>data>computed>watch
简单的说:key是虚拟DOM对象的标识,在更新显示时key起着极其重要的作用。
复杂的说:当状态中的数据发生了变化时,react会根据【新数据】生成【新的虚拟DOM】,随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:
旧虚拟DOM中找到了与新虚拟DOM相同的key
1.若虚拟DOM中的内容没有变,直接使用之前的真是DOM
2.若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
旧虚拟DOM中未找到与新虚拟DOM相同的key
1.根据数据创建新的真实DOM,随后渲染到页面
我们在开发过程中会碰到数据更新,但是视图并未改变的情况,情况如下:
第一种:动态给对象新增属性或者删除属性是不会触发视图刷新的,Vue识别不到;
第二种:通过数组下标修改数组中的元素或者手动修改数组的长度,Vue识别不到;
① 可以利用this.$set() this.$set(this.arr, 0, "列表0")
② 可以利用vue对数组重写的splice方法 this.arr.splice(0, 1, "列表0")
③ 重新声明一个变量深拷贝一下当前这个数组然后重新赋值即可
4 可以利用Object.assign()方法 (对象)
mixins是一种分发 Vue 组件中可复用功能的非常灵活的方式。混合对象可以包含任意组件选项。当组件使用混合对象时,所有混合对象的选项将被混入该组件本身的选项。
而mixins引入组件之后,则是将组件内部的内容如data等方法、method等属性与父组件相应内容进行合并。相当于在引入后,父组件的各种属性方法都被扩充了。
相同点:
v-show和v-if都能控制元素的显示和隐藏。
不同点:
1.实现本质方法不同:v-show本质就是通过设置css中的display设置为none;控制隐藏v-if是动态的向DOM树内添加或者删除DOM元素;
2.v-show都会编译,初始值为false,只是将display设为none,但它也编译了;v-if初始值为false,就不会编译了
总结:v-show只编译一次,后面其实就是控制css,而v-if不停的销毁和创建,如果要频繁切换某节点时,故v-show性能更好一点。
vue2.x版本中,当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级;
vue3.x版本中,当 v-if 与 v-for 一起使用时,v-if 具有比 v-for 更高的优先级。
官网明确指出:避免 v-if 和 v-for 一起使用,永远不要在一个元素上同时使用 v-if 和 v-for。
可以先对数据在计算数据中进行过滤,然后再进行遍历渲染;
操作和实现起来都没有什么问题,页面也会正常展示。但是会带来不必要的性能消耗;
在一个组件实例中,只有在data里初始化的数据才是响应的,Vue不能检测到对象属性的添加或删除,没有在data里声明的属性不是响应的,所以数据改变了但是不会在页面渲染;
解决办法:
使用 Vue.set(object, key, value) 方法将响应属性添加到嵌套的对象上
由于 Vue 无法探测对象新增属性或者通过索引为数组新增一个元素,所以这才有了 vm.s e t , 它 是 V u e . s e t 的 别 名 。 v m . set,它是 Vue.set 的别名。 vm.set,它是Vue.set的别名。vm.set 用于向响应式对象添加一个新的 property,并确保这个新的 property 同样是响应式的,并触发视图更新。
为对象添加一个新的响应式数据:调用 defineReactive 方法为对象增加响应式数据,然后执行 dep.notify 进行依赖通知,更新视图
为数组添加一个新的响应式数据:通过 splice 方法实现
< keep-alive >是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。
< keep-alive > 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
如果应用够简单,最好不要使用 Vuex,一个简单的 store 模式即可;
需要构建一个中大型单页应用时,使用Vuex能更好地在组件外部管理状态;
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
每个mutation执行完成后都会对应到一个新的状态变更,这样devtools就可以打个快照存下来,然后就可以实现 time-travel 了。如果mutation支持异步操作,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难
编码阶段
SEO优化
打包优化
vue3
相比vue2
Dom
实现通过webpack
的tree-shaking
功能,可以将无用模块“剪辑”,仅打包需要的
能够tree-shaking
,有两大好处:
compositon Api
Options API
一起使用Vue3
模块可以和其他框架搭配使用 Typescript更易使用
响应式 Api
暴露出来
composition Api,也就是组合式api
,通过这种形式,我们能够更加容易维护我们的代码,将相同功能的变量进行一个集中式的管理
Options Api
包含一个描述组件选项(data、methods、props等)的对象 options;
API开发复杂组件,同一个功能逻辑的代码被拆分到不同选项 ;
使用mixin重用公用代码,也有问题:命名冲突,数据来源不清晰;
Composition Api
vue3 新增的一组 api,它是基于函数的 api,可以更灵活的组织组件的逻辑。
解决options api在大型项目中,options api不好拆分和重用的问题。
1.el-cascader多选在IE中样式不正常
2.级联选择器高度问题
3.Table 固定列下出现线条
普通DOM元素进行底层操作的时候,可以使用自定义指令 鼠标聚焦,下拉菜单,相对时间转换,滚动动画
自定义指令是用来操作DOM的。尽管Vue推崇数据驱动视图的理念,但并非所有情况都适合数据驱动。自定义指令就是一种有效的补充和扩展,不仅可用于定义任何的DOM操作,并且是可复用的。
添加自定义指令的两种方式:
全局指令: 通过 Vue.directive() 函数注册一个全局的指令。
局部指令:通过组件的 directives 属性,对该组件添加一个局部的指令。
Vue 初始化页面闪动问题如何解决:
出现该问题是因为在 Vue 代码尚未被解析之前,尚无法控制页面中 DOM 的显示,所以会看见模板字符串等代码。
解决方案是,在 css 代码中添加 v-cloak 规则,同时在待编译的标签上添加 v-cloak 属性
Vue 组件间通信有哪几种方式
指令本质上是装饰器,是 vue 对 HTML 元素的扩展,给 HTML 元素增加自定义功能。vue 编译 DOM 时,会找到指令对象,执行指令的相关方法。
自定义指令有五个生命周期(也叫钩子函数),分别是 bind、inserted、update、componentUpdated、unbind
原理
当前元素添加 directives 属性,通过 genDirectives 生成指令代码,
1snabbdom生成vnode:h函数通过vnode函数,最终返回一个对象
2 patch函数。先判断传入参数是vnode还是dom。 (sameVnode)再判断vnode是否相同,比较key 和 selector 都相同再调用 patchVnode 进行后续比较,否则直接删除重建 patch 函数: 相同(sel 和 key 都相同) 删除 oldVnode / 重建 vnode
3patchVnode函数 children: text children
4 updateChildren函数
(开始与开始做对比)对比,(sameVnode) 结束与结束做对比) 开始与结束做对比 (结束与开始做对比) 四种情况都没有命中 直接对题 对比 key 新建节点
vue模板=》render函数=》vnode=》进行patch和diff
对于Vue来说,我们所认为的“HTML”其实都是字符串。
Vue会根据其规定的模板语法规则,将其解析成AST语法树;
然后会对这个大对象进行一些初步处理,比如标记没有动态绑定值的节点;
最后,会把这个大对象编译成render函数,并将它绑定在组件的实例上。
这样,我们所认为的“HTML”就变成了JavaScript代码,可以基于JavaScript模块规则进行导入导出,在需要渲染组件的地方,就调用render函数,根据组件当前的状态生成虚拟dom,然后就可以根据这个虚拟dom去更新视图了。
1.组件是独立和可复用的代码组织单元。组件系统是Vue核心特性之一,它使开发者使用小型、独立和通常可复用的组件构建大型应用;
2.组件化开发能大幅提高应用开发效率、测试性、复用性等;
3.组件使用按分类有:页面组件、业务组件、通用组件;
4.vue的组件是基于配置的,我们通常编写的组件是组件配置而非组件,框架后续会生成其构造函数,它们基于VueComponent,扩展于Vue;
5.vue中常见组件化技术有:属性prop,自定义事件,插槽等,它们主要用于组件通信、扩展等;6合理的划分组件,有助于提升应用性能;
6.组件应该是高内聚、低耦合的;
7.遵循单向数据流的原则。