Vue2知识点 - RT
vue中 获取token 实现token登陆
参考: https://blog.csdn.net/weixin_48255917/article/details/110622736深入响应式原理
当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。
每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
解决Vue不能检测对象,数据的变化
对象
Vue.set(vm.someObject, ‘b’, 2) 或者 this.$ set(this.someObject,‘b’,2)
数组
vm.$ set(vm.items, indexOfItem, newValue) 或者 vm.items.splice(indexOfItem, 1, newValue)
详见官网: https://cn.vuejs.org/v2/guide/reactivity.html#%E5%AF%B9%E4%BA%8E%E5%AF%B9%E8%B1%A1解决A,B组件循环引用问题
components:{aaaComponent:()=>import(‘./……’)
}
- 定义一个全局函数,用于清空dialog中数据
utils文件夹中新建一个globalFunction.js
exports.install = function(Vue) {//重置dialog数据,data为缓存数据,originalData为原数据Vue.propotype.globalResetData = function(data, originalData) {Object.assign(data, originalData)}//清空表单校验,ref为表单引用,vm为this实例Vue.prototype.globalClearValidate = function(ref, vm) {vm.$ref[ref].clearValidate()}
}main.js中
import globalFunction from ‘@/utils/globalFunction.js’
Vue.use(globalFunction)组件中
clearData(){this.globalResetData(this.$data, this.$options.data.call(this))this.globalClearValidate(‘basicInfoRef’, this)
}备注:这里之所以使用.call()
参考: http://blog.csdn.net/mocoe/article/details/89682022
Javascript call方法
(1)call()方法是预定义的javascript方法。
(2)它可以用来调用所有者对象作为参数的方法。
(3)通过call(),你可以使用属于另一个对象的方法。JS中判断数据类型
一般采用typeof 或者 instanceof
参考: https://blog.csdn.net/qq_40138556/article/details/103922078防抖和节流
使用 lodash 轻松实现防抖,节流。
主要目的是为了降低高频事件触发,减少dom操作或请求次数,提升性能。
防抖:func1: _.debounce(() => { }, 1000)
节流: func1: _.throttle(() => { }, 1000)
节流:在固定的时间内触发事件,每隔n秒触发一次。
防抖:当你频繁触发后,n秒内只执行一次。
参考:
(1)https://baijiahao.baidu.com/s?id=1714057873760606352&wfr=spider&for=pc
(2)https://blog.csdn.net/woleigequshawanyier/article/details/85345095
(3)https://blog.csdn.net/qq_42357338/article/details/107864044
有空手动写一遍vue-router路由跳转传参刷新页面后参数丢失问题
参考: https://blog.csdn.net/qq_41877050/article/details/122936868
另一个问题:
vue-router中query和params区别
参考: https://www.csdn.net/tags/MtTacg4sMzcwNjctYmxvZwO0O0OO0O0O.html
this.$ router.push中query传参,参数会显示在地址栏,类似于get请求.
this.$ router.push中params传参,push里只能是name,地址栏不显示参数,类似于post请求.babel作用
将es6代码转换为es5代码cookie localStorage sessionStorage
localStorage替代了sessionStorage
cookie有过期时间,localStorage没有。
cookie容量在4k左右,且有条数限制,localStorage容量有5M。
cookie会向服务器发送数据,localStorage不会。
cookie 存储的是字符串,localStorage存储的是对象。定时器 this指向问题
如果没有特殊指向,setInterval和setTineout的回调函数中this指向都是window
改变this指向有函数上头定义一个
let self = this
或者将这个函数改成箭头函数
改变this指向
函数内部this指向谁,不是在函数定义时决定的,而是在函数第一次调用并执行的时候决定的。
通过call,apply,bind可改变this指向vue2 状态管理
直接修改state数据(浅拷贝?)和通过mutations修改值(深拷贝?)
相同点:都能够触发视图更新
不同点:直接修改不会更改state
这样做优点是,使vuex能够记录每一次state变化,保存状态快照,实现时间漫游/回滚等操作。null 和 undefine 区别
typeof undefine // undefine
typeof null // object
null跟number运算可以得到值,
undefined跟number一起运算会得到NaN
null 特指对象的值未设置。
undefine 表示缺少值。flex有哪些用法
justify-content:center 水平居中
align-items:center 垂直居中
flex-direction 属性决定主轴方向
flex-wrap 如果一条轴线排不下,如何换行v-model原理
v-model等价于v-bind和v-on:input或者change
对于input和textareatext area元素使用value和input事件
对于checkbox和radio使用checked和change事件从哪几个方面提升页面性能
单页面应用当组件里面东西太多刷新会出现白屏,所以需要优化当前页面
(1)vue异步组件实现懒加载
component: resolve=>(require([需要加载的地址]), resolve)
(2)组件拆分,页面分为多个组件
(3)使用keep-alive切换路由
(4)图片懒加载v-lazy
(5)组件销毁之后将全局变量重置为null
(6)vue.config.js配置项中将productionSourceMap设置为false,不然最终打包会生成一些map文件。
(7)productionGzip设置为true可以开启gzip压缩,使打包过后体积变小。lodash实现深拷贝
lodash.cloneDeep()
lodash.clone()是浅拷贝
浅拷贝:如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,b拷贝的就是内存地址,所以如果其中一个对象改变了这个地址,就会影响另一个对象。
深拷贝:深拷贝会拷贝所有的属性,并拷贝指向的动态分配的内存。拷贝前后两个对象互不影响。深拷贝,浅拷贝,都有哪些
深拷贝和浅拷贝主要是针对对象的属性是对象
Array.from可以获取到一个数组的深拷贝
Object.assign也可以获取对象的深拷贝
这个方法当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝。但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。
JSON.parse(json.stringify(对象))是深拷贝
这个方法应该注意:
(1)如果obj里面存在时间对象,JSON.parse(JSON.strigify(obj))之后,时间对象变成了字符串
(2)如果obj里面有正则,Error对象,则序列化的结果会得到空对象
(3)如果obj里面有函数,undefine,则序列化的结果会把函数,undefine丢失
(4)如果obj里面有NaN,Infinity,则序列化的结果会变成null
(5)JSON.strigify()只能序列化对象的可枚举的自有属性。如果obj中的对象是由构造函数生成的,也深拷贝后,会丢失对象的constructor
(6)如果对象中存在循环引用的情况也无法正确实现深拷贝ES6有哪些新特性
(1)const let
(2)模板字符串
(3)箭头函数
(4)采用 || 来获取默认值
(5)…运算符
(6)数组和对象解构
(7)对象超类 super
(8)for…of / for…in怎么判断 {} 没有键值
JSON.stringify(data) 是不是== ‘{}’
或者获取下Object.keys(data),看它的长度是不是为0$bus使用
$bus叫做事件总线,只能用于在兄弟组件之间的传值,其他关系可以用vuex
main.js中,全局注册下
Vue.prototype.$bus = new Vue()
组件1中定义:
this.$bus.$on(‘updateData’, 数据)
组件2中调用:
this.$bus.$emit(‘updateData’, ….)
要注意在定义的组件中,及时卸载:
beforeDestory() {this.$bus.$off(‘updateData’, …)
}
用ES6数组去重
Array.from(new Set(arr))watch监听对象里的某个值
watch里有一个handler方法
有一个immediate属性,当值第一次绑定就进行监听。 还有一个deep属性,默认是false,设置为true才会开启深度监听。
’obj.name’: {
handler(newVal, oldVal) {
……
}, deep: true
}vuex里的数据 一刷新就重置了怎么解决
可以把这种数据,存储在localStorageH5新增了哪些新特性
画布canvas,视频video,音频audio 以及一些dom标签px em rem
使用em和rem可以控制元素整放大缩小
em和rem区别是浏览器根据谁来转化成px值
rem 单位翻译为像素值是由html元素的字体大小决定,此字体大小会被浏览器中字体大小的设置影响。
em 单位转为像素值取决于使用的字体大小,此字体大小受从父元素继承过来的字体大小影响。
rem 是相对于浏览器设置,使用rem主要目的应该是确保无论用户如何设置自己的浏览器,我们的布局都能调整到合适大小。
em 主要目的应该是允许保持在一个特定的设计元素范围内的可扩展性。
rem使用:
html {font-size:62.5%}
浏览器默认字体都是16px,
一般我们把跟元素的字体设置为10px方便计算relative和absolute
position中的属性,还有static,fixed
relative: 生成相对定位的元素
absolute: 生成绝对定位的元素
absolute一般用于使用导航栏或者底部需要固定的地方。 需要参照物,从父节点有设置position作为参照。
元素只设置relative,不设置top,right,left,bottom的值不会对元素有影响,还是原来的位置。W3C盒子模型(标准盒子模型)和怪异盒子模型(IE盒子模型)
盒子模型就是margin,border,padding,content
标准盒子模型的计算宽高是content的宽高
怪异盒子模型的计算宽高是border的宽高。路由守卫有哪些,怎么用的?
路由守卫就是路由跳转过程中的一些钩子函数。
全局路由守卫:
router.beforeEach(to,from,next) 全局前置路由守卫,路由跳转前触发。 可以在这里判断token是否存在,否则跳转到登陆页,也可以在这里记录to.path的点击次数。
beforeResolve(to,from,next) 全局解析守卫,在所有组件内守卫和异步路由组件被解析之后触发。
router.afterEach(to,from) 全局后置守卫,路由跳转后触发. 可以在这里设置下标题, window.scrollTo(0,0)等操作。
to:即将要进入的目标路由对象
from:即将离开的路由对象
next:是否进入某个具体路由,或者是某个具体路由的路径组件中data为什么是函数,而不是对象
方便组件复用
这并不是vue自身如此设计而是跟javascript特性相关。
JS中的实例是通过构造函数来创建的,每个构造函数可以new出很多个实例,那么每个实例都会继承原型上的方法或属性。
vue的data数据其实是vue原型的属性,数据存在于内存当中,vue为了保证每个实例上的data数据的独立性,规定了必须使用函数,而不是对象。
使用函数后,使用的是data()函数,data()函数中的this指向是当前实际本身。 多处引用这个组件就不会互相干扰。定时器放在哪个生命周期
在data中定义 timer: null
在mounted()中创建定时器
this.timer = window.setInterval(() => {//自定义要执行的代码
},1000)
在beforeDestory中清除
beforeDestory(){window.clearInterval(this.timer)
}
// keep-alive可以将Vue的路由组件都缓存起来,组件之间相互切换时,为了减轻浏览器运行负担,没必要每次都要销毁和重建.
<keep-alive><router-view></router-view>
</keep-alive>
一般项目都设置了,此时路由跳转时,组件不被销毁,那我们熟知的Vue生命周期函数beforeDestory和destoryed将不被执行.
这个时候就可以用上导航守卫了
beforeRouterLeaver(to, from, next){next()
if(this.timer){window.clearInterval(this.timer)
this.timer = null
}
}
或者在keep-alive下deactiveed中进行销毁
合并数组有哪些方法
(1)concat 需要用一个新的数组来接
(2)遍历其中一个数组,用另一个数组push
(3)采用三点运算符全局函数
(1)在main.js中直接写函数
Vue.prototype.test = function() {
console.log(‘执行了全局函数’)
}
组件中调用
this.test()
(2)写一个模板文件,挂载到main.js上
// base.js
exports.install = function(Vue) {
Vue.prototype.test1 = function() {
console.log(‘执行了test1函数’)
}
Vue.prototype.test2 = function() {
console.log(‘执行了test2函数’)
return ‘12345’
}
}
main.js中:
import base from ……
Vue.use(base) //将全局函数当作插件来使用
组件里调用:
this.test1()
let res = this.test2()SPA页面优化
传统多页面是由后端控制一个url对应一个html文件,页面之间跳转需要根据后端给出的url跳转到html上,几乎每一个响应都会刷新整个页面。缺点是:不能很好重用公共文件,页面之间切换加载缓慢,流畅度不够。
单页面应用(single page application)就是只有一个页面的应用,页面的刷新跳转完全由JS定义的路由来控制。所有文件只会加载一次,最大限度重用文件。
常见SPA首屏优化方式:
(1)减少入口文件体积
vue异步组件技术-异步加载
{path:’/home’, name:’home’, component: resolve => require([‘@/components/home’], resolve)}
组件懒加载技术-路由懒加载,使用import
{path:’/home’, name:’home’, component: () => import(’@/components/home’)}
(2)静态资源本地缓存
后端返回资源问题
采用HTTP缓存,设置Cache-control,Last-Modified,Etag等响应头。
采用Service Worker离线缓存。
前端合理利用localStorage
(3)UI框架按需加载
(4)图片资源的压缩
对页面上使用到icon,可以使用雪碧图,将众多小图标合并到同一张图上,用以减轻http请求压力。怎么监听vuex中的状态
在组件中通过赋值等于this.$ store.state.属性的形式不能正确监听。
可以直接
‘$store.state.属性’: {handle(newVal, oldVal) {......}, immediate:true
}
标准盒子模型和怪异盒子模型怎么转换
在html中,只要在顶部声明了DOCTYPE,默认都会使用标准盒子模型。如果没有声明,则会根据浏览器类型自行调整。
在CSS中对相应的div盒子进行box-sizing属性的设置,就可以让盒模型在标准和怪异中进行转换。
box-sizing: content-box; 盒模型设置为w3c标准盒子模型。
box-sizing: border-box; 盒模型设置为怪异盒子模型。路由传值,通过url传值
this.$ router.push
跳转到指定url路径,并想history栈中添加一个记录,点击后退会返回到上一个页面
this.$ router.replace
跳转到指定url路径,但是history栈中不会有记录,点击返回会跳转到上上个页面 (就是直接替换了当前页面)
this.$ router.go(n)
向前或者向后跳转n个页面,n可为正整数或负整数
$ router : 是路由操作对象,只写对象
$ route : 路由信息对象,只读对象
$ router 操作路由跳转
this.$ router.push({ name:‘hello’, params:{ name:‘word’, age:‘11’ } })
$ route读取 路由参数接收
let name = this.$ route.params.name;vue2对数组进行push,unshift和splice会对插入的数据再次进行观测,调用内部的observeArray方法
不会导致页面渲染的操作:
(1)利用索引直接改变一个值,this.arr[0] = 100
(2)修改数组的长度,this.arr.length = 100
通过索引改变数组,可以通过this.$ set(this.arr, 0, 100)来渲染页面
this.$ set实现原理:
(1)如果是数组,直接通过数组的splice方法触发响应式。
(2)如果是对象,通过defineReactive方法进行响应式处理(defineReactive方法就是Vue在初始化对象时,给对象属性采用Object.defineProperty动态添加getter和setter的功能所调用的方法)css中 ::before ::after
::before 伪元素可以在元素的内容前面插入新的内容
::after 伪元素可以在元素的内容之后插入新的内容created生命周期
执行这个函数时,vue实例已经初始化了,可以在这里调用数据,不过还没渲染到页面上。此时会将data中的属性和methods中的方法添加到vue实例身上,同时,会将data中所有的属性添加一个getter/setter方法。
mounted 创建完成,页面渲染完毕。此时可以通过$ref来访问真实的DOM结构。在生命周期里通过this来访问data数据原理
Vue2通过Object.defineProperty把data上的属性代理到vm上,vm即this对象,所以可以通过this. 来访问data的数据。vue项目处理跨域问题
产生跨域的原因:如果a,b页面的协议,域名,端口号,子域名不同,所进行的访问都是跨域。
proxy原理?需要再看看
(1)在vue.config.js中配置proxy代理
有个target,pathRewrite
(2)vue打包部署后,通过配置nginx代理跨域中的同源
协议,ip地址(域名),端口号全部相同,就是同源。
例如:
http://localhost:8080/index 和
http://localhost:8080/home
协议,ip地址(域名),端口号任意一项不同就是不同源。
例如:
http://localhost:8080/index
https://localhost:8080/index
http://localhost:8090/indexproxy跨域原理
浏览器会因为同源策略跨域,但服务器不禁止,npm run dev本来就是运行了服务器,所以利用服务器发送请求即可,将所有请求转发到自己的node服务器然后发送请求,即代理。vue页面怎么渲染的
生成render 函数,生成vnode ,将虚拟节点patch(vnode)到绑定元素上。
虚拟DOM也就是我们常说的虚拟节点,他是通过JS的Object对象模拟DOM中的节点,然后在通过特定的render方法将其渲染成真实的DOM节点。rem
经常看到body{font-size: 62.5%}
由于绝大多数浏览器默认font-size:16px;
经过上面设置,1rem=10px,1.6rem=16pxVue和React对比
React对于原生JS要求高一点. 国外React用的多,国内Vue更多.
共同点:
组件
单向数据流,数据驱动视图
Virtual DOM
社区成熟,都支持SSR(Server-Side Rendering, 服务端渲染,在服务端将 Web 应用渲染成 HTML)
不同点:
Vue使用模板拥抱html, React使用JSX拥抱JS
Vue"自动挡", React"手动挡"(api和生态)
Vue各种相关api,插件写的很好,更友好, React则更自由,它倡导自由集成功能.
为什么大公司喜欢用React?
上限高一点,自由一点.
Vue3慢慢靠近React写法.前端安全 CSRF
cross-site request forgery 跨站请求伪造
简单来说就是攻击者以你的身份去伪造恶意请求,比如以你的身份去q发送邮件,消息,盗取账户信息甚至购买商品,网上转账等。
参考:
https://blog.csdn.net/OriginalMIxss/article/details/120944619axios拦截器设置token
axios.interceptors.request.use(config=>{
// 为请求头对象添加token验证的authorization字段
config.headers.Authorization = window.localStorage.getItem(‘token’)
return config
})v-html xss风险
下载vue-dompurify-html
main.js中
import VueDOMPurifyHTML from ‘vue-dompurify-html’
Vue.use(VueDOMPurifyHTML)
页面中
<span v-dompurify-html></span>
浏览器怎么通过输入一个url请求到页面的
输入url,浏览器进行解析,建立TCP连接,发送http request请求,web服务器发送nginx反向代理,请求到应用服务器,发送到浏览器,浏览器进行响应渲染,关闭TCP连接,响应完成,这个是非持久连接。webpack 常见配置
设置文件路径
然后可以设置绝对路径别名
chainWebpack: (config)=>{config.resolve.alias.set(‘@‘, resolve(‘./src’)).set(‘_c’, resolve(‘./src/components’))
}
设置eslint
lintOnSave: true
打包时不生成.map文件
productionSourceMap: false
通过写接口的基础路径解决前端跨域
devServer: { proxy {target: ‘ http://192.0.0.0:8080 ‘,pathRewrite: {‘^api’: ‘/‘ }} }
Vue为什么要使用template
(Vue在原生html中,通过Vue.component创建的。)
Vue官网介绍template:
一个字符串模板,用作component实例的标记。模板将会替换所挂载元素的innerHtml。JS中,怎么区分对象和数组
通过typeof它们都返回object
(1)Array.isArray(arr) // true
Array.isArray(obj) // false
(2) arr.constructor == Array // true
obj.constructor == Object // true
(3) arr instanceof Array // true
obj instanceof Array // falseJS中一共8种数据类型
字符串 String
数值 Number
布尔值 Boolean
空值 Null
未定义 Undefined
对象 Object
还有 独一无二的值Symbol,任意大的整数BigInt
使用typeof 来判断数据类型get和post最主要区别
功能不同:
get是从服务器上获取数据
post是向服务器传送数据跨域请求时,会先发一个options预请求
options 请求就是预检请求,可用于检测服务器允许的 http 方法。当发起跨域请求时,由于安全原因,触发一定条件时浏览器会在正式请求之前自动先发起 OPTIONS 请求,即 CORS 预检请求,服务器若接受该跨域请求,浏览器才继续发起正式请求。
参考: https://blog.csdn.net/weixin_43822787/article/details/121036722前端proxy和后端proxy区别
当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同时就会造成跨域
跨域问题一般有两种解决思路:
正向代理:“一台代理服务器"代替了"客户端”,去和"目标服务器"进行交互,即代理客户端。用途:隐藏客户端真实IP,突破限制访问外国网站。
反向代理:“一台代理服务器"代替了"目标服务器”,去和"客户端"进行交互,即代理服务端用途:隐藏服务器真实IP,提供负载平衡,即指向后端的多台服务器中空闲的一台;而我们一般在开发中解决跨域是利用反向代理的原理。例如vue项目中配置proxy代理或者nginx配置反向代理。
参考: https://blog.csdn.net/qq_38974163/article/details/121396279打包工具
rollup, webpack, vite
rollup更适合打包库,webpack更适合打包项目,vite基于rollup实现了热更新也适合打包项目。
看一下
https://www.bilibili.com/video/BV1bq4y117Hz?spm_id_from=333.999.0.0单例模式
单例模式的意思是,保证一个类只有一个实例,并且有一个接口供全局访问。它的作用就是防止频繁创建实例,浪费不必要的内存空间和资源消耗,那它有什么实用场景呢,假如我们在页面中有一个点击跳出一个弹窗操作,弹窗应该是唯一的,无论点击多少次它都应该被构建一次,那么这个弹窗就适合用单例模式来创建。
系统看一下JS设计模式
参考: https://blog.csdn.net/SK_study/article/details/122391837reduce用法
reduce() 方法接收一个函数作为累加器,reduce 为数组中的每一个元素依次执行回调函数,
不包括数组中被删除或从未被赋值的元素。
const arr = [1, 2, 3, 4, 5]
const sum = arr.reduce((prev, cur) => {
return prev + cur
}, 0)
console.log(sum) // 15
还可以用于数组去重等操作
参考: https://blog.csdn.net/qq_43205326/article/details/109729520SaaS项目
Saas平台是运营saas软件的平台。SaaS提供商为企业搭建信息化所需要的所有网络基础设施及软件、硬件运作平台,并负责所有前期的实施、
后期的维护等一系列服务,企业无需购买软硬件、建设机房、招聘IT人员,即可通过互联网使用信息系统。SaaS 是一种软件布局模型,
其应用专为网络交付而设计,便于用户通过互联网托管、部署及接入。Vue性能优化
1)编码阶段
尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher;
如果需要使用v-for给每项元素绑定事件时使用事件代理;
SPA 页面采用keep-alive缓存组件;
在更多的情况下,使用v-if替代v-show;
key保证唯一;
使用路由懒加载、异步组件;
防抖、节流;
第三方模块按需导入;
长列表滚动到可视区域动态加载;
图片懒加载;
2)用户体验:
骨架屏;
PWA;
还可以使用缓存(客户端缓存、服务端缓存)优化、服务端开启gzip压缩等。
3)SEO优化
预渲染;
服务端渲染SSR;
4)打包优化
压缩代码;
Tree Shaking/Scope Hoisting;
使用cdn加载第三方模块;
多线程打包happypack;
splitChunks抽离公共文件;
sourceMap优化;v-model的原理是什么?
v-model本质就是一个语法糖,可以看成是value + input方法的语法糖。可以通过model属性的prop和event属性来进行自定义。原生的v-model,会根据标签的不同生成不同的事件和属性。
v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:
1)text 和 textarea 元素使用 value 属性和 input 事件;
2)checkbox 和 radio 使用 checked 属性和 change 事件;
3)select 字段将 value 作为 prop 并将 change 作为事件。如何理解自定义指令?
指令的实现原理,可以从编译原理 =>代码生成=> 指令钩子实现进行概述
1、在生成 ast 语法树时,遇到指令会给当前元素添加directives属性
2、通过 genDirectives 生成指令代码
3、在patch前将指令的钩子提取到 cbs中,在patch过程中调用对应的钩子。
4、当执行指令对应钩子函数时,调用对应指令定义的方法computed 和 watch 的区别和运用的场景?
computed: 计算属性。依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值;
watch: 监听数据的变化。更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;
运用场景:
1)当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
2)当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。v-if与v-show的区别
v-if 是真正的条件渲染,直到条件第一次变为真时,才会开始渲染。
v-show 不管初始条件是什么会渲染,并且只是简单地基于 CSS 的 “display” 属性进行切换。
注意:v-if 适用于不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景。v-if 与 v-for的优先级
1、v-for优先于v-if被解析
2、如果同时出现,每次渲染都会先执行循环再判断条件,无论如何循环都不可避免,浪费了性能
3、要避免出现这种情况,则在外层嵌套template,在这一层进行v-if判断,然后在内部进行v-for循环
4、如果条件出现在循环内部,可通过计算属性提前过滤掉那些不需要显示的项Vue 中的diff原理
vue的diff算法是平级比较,不考虑跨级比较的情况。内部采用深度递归的方式 + 双指针的方式进行比较。
补充回答:
1)先比较是否是相同节点
2)相同节点比较属性,并复用老节点
3)比较儿子节点,考虑老节点和新节点儿子的情况
4)优化比较:头头、尾尾、头尾、尾头
5)比对查找进行复用
Vue2 与 Vue3.x 的diff算法:
Vue2的核心Diff算法采用了双端比较的算法,同时从新旧children的两端开始进行比较,借助key值找到可复用的节点,再进行相关操作。
Vue3.x借鉴了ivi算法和 inferno算法,该算法中还运用了动态规划的思想求解最长递归子序列。(实际的实现可以结合Vue3.x源码看。)Vue中key的作用和工作原理,说说你对它的理解
例如:v-for=“(item, itemIndex) in tabs” :key=“itemIndex”
key的作用主要是为了高效的更新虚拟DOM,其原理是vue在patch过程中通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个patch过程更加高效,减少DOM操作量,提高性能。
补充回答:
(1)若不设置key还可能在列表更新时引发一些隐蔽的bug
(2)vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。Vue 为什么需要虚拟DOM? 虚拟DOM的优劣如何?
Virtual DOM 就是用js对象来描述真实DOM,是对真实DOM的抽象,由于直接操作DOM性能低但是js层的操作效率高,可以将DOM操作转化成对象操作,最终通过diff算法比对差异进行更新DOM (减少了对真实DOM的操作)。虚拟DOM不依赖真实平台环境从而也可以实现跨平台。
补充回答:
虚拟DOM的实现就是普通对象包含tag、data、children等属性对真实节点的描述。(本质上就是在JS和DOM之间的一个缓存)
Vue2的 Virtual DOM 借鉴了开源库snabbdom的实现。
VirtualDOM映射到真实DOM要经历VNode的create、diff、patch等阶段。nextTick在哪里使用?原理是?
nextTick的回调是在下次DOM更新循环结束之后执行的延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM。nextTick主要使用了宏任务和微任务。原理就是异步方法(promise, mutationObserver, setImmediate, setTimeout)经常与事件循环一起来问。
补充回答:
vue多次更新数据,最终会进行批处理更新。内部调用的就是nextTick实现了延迟更新,用户自定义的nextTick中的回调会被延迟到更新完成后调用,从而可以获取更新后的DOM。vue-router 两种模式的区别?
vue-router 有 3 种路由模式:hash、history、abstract。
1)hash模式:hash + hashChange
特点:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无用,hash不会重加载页面。通过监听 hash(#)的变化来执行js代码 从而实现 页面的改变。
核心代码:
window.addEventListener(‘hashchange‘,function(){
self.urlChange()
})
2)history模式:historyApi + popState
HTML5推出的history API,由pushState()记录操作历史,监听popstate事件来监听到状态变更;
因为 只要刷新 这个url(www.ff.ff/jjkj/fdfd/fdf/fd)就会请求服务器,然而服务器上根本没有这个资源,所以就会报404,解决方案就 配置一下服务器端。
说明:
(1)hash: 使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器;
(2)history : 依赖 HTML5 History API 和服务器配置。具体可以查看 HTML5 History 模式;
(3)abstract : 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式.Vue-router有几种钩子函数?具体是什么及执行流程是怎样的?
路由钩子的执行流程,钩子函数种类有:全局守卫、路由守卫、组件守卫。
完整的导航解析流程
1.导航被触发;
2.在失活的组件里调用beforeRouteLeave守卫;
3.调用全局beforeEach守卫;
4.在复用组件里调用beforeRouteUpdate守卫;
5.调用路由配置里的beforeEnter守卫;
6.解析异步路由组件;
7.在被激活的组件里调用beforeRouteEnter守卫;
8.调用全局beforeResolve守卫;
9.导航被确认;
10.调用全局的afterEach钩子;
11.DOM更新;
12.用创建好的实例调用beforeRouteEnter守卫中传给next的回调函数。keep-alive平时在哪里使用?原理是?
keep-alive 主要是组件缓存,采用的是LRU算法。最近最久未使用法。
常用的两个属性include/exclude,允许组件有条件的进行缓存。
两个生命周期activated/deactivated,用来得知当前组件是否处于活跃状态。Vue 组件间通信有哪几种方式?
Vue 组件间通信只要指以下 3 类通信:父子组件通信、隔代组件通信、兄弟组件通信,下面我们分别介绍每种通信方式且会说明此种方法可适用于哪类组件间通信。
1、props / $ emit 适用 父子组件通信
2、ref 与 $ parent / $ children 适用 父子组件通信
1)ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
2)$ parent / $ children:访问父 / 子实例
3、EventBus ($ emit / $ on) 适用于 父子、隔代、兄弟组件通信
这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件。
4、$ attrs/$ listeners 适用于 隔代组件通信
1)$ attrs:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 ( class 和 style 除外 )。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 ( class 和 style 除外 ),并且可以通过 v-bind=“$ attrs” 传入内部组件。通常配合 inheritAttrs 选项一起使用。
2)$ listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on=“$ listeners” 传入内部组件
5、provide / inject 适用于 隔代组件通信
祖先组件中通过 provider 来提供变量,然后在子孙组件中通过 inject 来注入变量。provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
6、Vuex 适用于 父子、隔代、兄弟组件通信
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。Vue中的组件的data 为什么是一个函数?
每次使用组件时都会对组件进行实例化操作,并且调用data函数返回一个对象作为组件的数据源。这样可以保证多个组件间数据互不影响。
如果data是对象的话,对象属于引用类型,会影响到所有的实例。所以为了保证组件不同的实例之间data不冲突,data必须是一个函数。Vue 的父组件和子组件生命周期钩子执行顺序
第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子。
渲染过程:
父组件挂载完成一定是等子组件都挂载完成后,才算是父组件挂载完,所以父组件的mounted在子组件mouted之后
父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
子组件更新过程:
影响到父组件:父beforeUpdate -> 子beforeUpdate->子updated -> 父updted
不影响父组件:子beforeUpdate -> 子updated
父组件更新过程:
影响到子组件:父beforeUpdate -> 子beforeUpdate->子updated -> 父updted
不影响子组件:父beforeUpdate -> 父updated
销毁过程:
父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed
重要:父组件等待子组件完成后,才会执行自己对应完成的钩子。生命周期钩子是如何实现的?
Vue的生命周期钩子就是回调函数而已,当创建组件实例的过程中会调用对应的钩子方法。
补充回答:
内部主要是使用callHook方法来调用对应的方法。核心是一个发布订阅模式,将钩子订阅好(内部采用数组的方式存储),在对应的阶段进行发布。Vue的生命周期方法有哪些?一般在哪一步发起请求及原因
总共分为8个阶段:创建前/后,载入前/后,更新前/后,销毁前/后。
1、创建前/后:
1)beforeCreate阶段:vue实例的挂载元素el和数据对象data都为undefined,还未初始化。
说明:在当前阶段data、methods、computed以及watch上的数据和方法都不能被访问。
2)created阶段:vue实例的数据对象data有了,el还没有。
说明:可以做一些初始数据的获取,在当前阶段无法与Dom进行交互,如果非要想,可以通过vm.$ nextTick来访问Dom。
2、载入前/后:
1)beforeMount阶段:vue实例的$ el和data都初始化了,但还是挂载之前为虚拟的dom节点。
说明:当前阶段虚拟Dom已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触发updated。
2)mounted阶段:vue实例挂载完成,data.message成功渲染。
说明:在当前阶段,真实的Dom挂载完毕,数据完成双向绑定,可以访问到Dom节点,使用$refs属性对Dom进行操作。
3、更新前/后:
1)beforeUpdate阶段:响应式数据更新时调用,发生在虚拟DOM打补丁之前,适合在更新之前访问现有的DOM,比如手动移除已添加的事件监听器。
说明:可以在当前阶段进行更改数据,不会造成重渲染。
2)updated阶段:虚拟DOM重新渲染和打补丁之后调用,组成新的DOM已经更新,避免在这个钩子函数中操作数据,防止死循环。
说明:当前阶段组件Dom已完成更新。要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新。
4、销毁前/后:
1)beforeDestroy阶段:实例销毁前调用,实例还可以用,this能获取到实例,常用于销毁定时器,解绑事件。
说明:在当前阶段实例完全可以被使用,我们可以在这时进行善后收尾工作,比如清除计时器。
2)destroyed阶段:实例销毁后调用,调用后所有事件监听器会被移除,所有的子实例都会被销毁。
说明:当前阶段组件已被拆解,数据绑定被卸除,监听被移出,子实例也统统被销毁。
补充回答:
第一次页面加载时会触发:beforeCreate, created, beforeMount, mounted。
1)created 实例已经创建完成,因为它是最早触发的原因可以进行一些数据,资源的请求。(服务器渲染支持created方法)
2)mounted 实例已经挂载完成,可以进行一些DOM操作。(接口请求)Proxy 与 Object.defineProperty 对比
Proxy 的优势如下:
1)Proxy 可以直接监听对象而非属性;
2)Proxy 可以直接监听数组的变化;
3)Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的;
4)Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;Vue中模板编译原理?
如何将template转换成render函数(这里要注意的是我们在开发时尽量不要使用template,因为将template转化成render方法需要在运行时进行编译操作会有性能损耗,同时引用带有complier包的vue体积也会变大) 默认.vue文件中的 template处理是通过vue-loader 来进行处理的并不是通过运行时的编译。
1)将 template 模板转换成 ast 语法树 - parserHTML
2)对静态语法做静态标记 - markUp
3)重新生成代码 - codeGen
补充回答:
模板引擎的实现原理就是new Function + with来进行实现的。
vue-loader中处理template属性主要靠的是 vue-template-compilerVue.set 方法是如何实现的?
为什么$set可以触发更新,我们给对象和数组本身都增加了dep属性,当给对象新增不存在的属性则触发对象依赖的watcher去更新,当修改数组索引时我们调用数组本身的splice方法去更新数组。
补充回答:
官方定义 Vue.set(object, key, value)
1)如果是数组,调用重写的splice方法(这样可以更新视图 )
代码:target.splice(key, 1, val)
2)如果不是响应式的也不需要将其定义成响应式属性。
3)如果是对象,将属性定义成响应式的 defineReactive(ob.value, key, val)
通知视图更新 ob.dep.notify()Vue如何检测数组变化?
数组考虑性能原因没有用defineProperty对数组的每一项进行拦截,而是选择重写数组 方法以进行重写。当数组调用到这 7 个方法的时候,执行 ob.dep.notify() 进行派发通知 Watcher 更新;
重写数组方法:push/pop/shift/unshift/splice/reverse/sort
补充回答:
在Vue中修改数组的索引和长度是无法监控到的。需要通过以下7种变异方法修改数组才会触发数组对应的wacther进行更新。数组中如果是对象数据类型也会进行递归劫持。
说明:那如果想要改索引更新数据怎么办?
可以通过Vue.set()来进行处理 -> 核心内部用的是 splice 方法。请说一下响应式数据的理解?
根据数据类型来做不同处理,数组和对象类型当值变化时如何劫持。
1)对象内部通过defineReactive方法,使用 Object.defineProperty() 监听数据属性的 get 来进行数据依赖收集,再通过 set 来完成数据更新的派发;
2)数组则通过重写数组方法来实现的。扩展它的 7 个变更⽅法,通过监听这些方法可以做到依赖收集和派发更新;( push/pop/shift/unshift/splice/reverse/sort )
这里在回答时可以带出一些相关知识点 (比如多层对象是通过递归来实现劫持,顺带提出vue3中是使用 proxy来实现响应式数据)
补充回答:
内部依赖收集是怎么做到的,每个属性都拥有自己的dep属性,存放他所依赖的 watcher,当属性变化后会通知自己对应的 watcher去更新。
响应式流程:
1、defineReactive 把数据定义成响应式的;
2、给属性增加一个 dep,用来收集对应的那些watcher;
3、等数据变化进行更新
dep.depend() // get 取值:进行依赖收集
dep.notify() // set 设置时:通知视图更新
这里可以引出性能优化相关的内容:1)对象层级过深,性能就会差。2)不需要响应数据的内容不要放在data中。3)object.freeze() 可以冻结数据。Vue.use是干什么的?原理是什么?
vue.use 是用来使用插件的,我们可以在插件中扩展全局组件、指令、原型方法等。
1、检查插件是否注册,若已注册,则直接跳出;
2、处理入参,将第一个参数之后的参数归集,并在首部塞入 this 上下文;
3、执行注册方法,调用定义好的 install 方法,传入处理的参数,若没有 install 方法并且插件本身为 function 则直接进行注册;
(1)插件不能重复的加载
install 方法的第一个参数是vue的构造函数,其他参数是Vue.set中除了第一个参数的其他参数; 代码:args.unshift(this)
(2)调用插件的install 方法 代码:typeof plugin.install === ‘function’
(3)插件本身是一个函数,直接让函数执行。 代码:plugin.apply(null, args)
(4)缓存插件。new Vue() 发生了什么?
1)结论:new Vue()是创建Vue实例,它内部执行了根实例的初始化过程。
2)具体包括以下操作:
选项合并
$ children,$ refs,$ slots,$ createElement等实例属性的方法初始化
自定义事件处理
数据响应式处理
生命周期钩子调用 (beforecreate created)
可能的挂载
3)总结:new Vue()创建了根实例并准备好数据和方法,未来执行挂载时,此过程还会递归的应用于它的子组件上,最终形成一个有紧密关系的组件实例树。对 SPA 单页面的理解,优缺点是什么?
SPA( single-page application )仅在 Web ⻚⾯初始化时加载相应的 HTML、JavaScript 和 CSS。⼀旦⻚⾯加载完成,SPA 不会因为⽤户的操作⽽进⾏⻚⾯的重新加载或跳转;取⽽代之的是利⽤路由机制实现 HTML 内容的变换,UI 与⽤户的交互,避免⻚⾯的重新加载。
优点:
1)⽤户体验好、快,内容的改变不需要重新加载整个⻚⾯,避免了不必要的跳转和重复渲染;
2)SPA 相对对服务器压⼒⼩;
3)前后端职责分离,架构清晰,前端进⾏交互逻辑,后端负责数据处理;
缺点:
1)⾸屏(初次)加载慢:为实现单⻚ Web 应⽤功能及显示效果,需要在加载⻚⾯的时候将JavaScript、CSS 统⼀加载,部分⻚⾯按需加载;
2)不利于 SEO:由于所有的内容都在⼀个⻚⾯中动态替换显示,所以在 SEO 上其有着天然的弱势。在router目录中写一个permission.js
路由守卫相关的代码
然后直接在main.js中 import ‘@/router/permission’ 生效element ui table实现拖拽
报了一个错:Sortable:’el’must be an HTML Element,not [Object Null]
原因是.el-table__body-wrapper 类名写错了
参考了: https://blog.csdn.net/shykevin/article/details/117102734vue获取token 实现token登陆
将获取到的token存储在本地localStorage和vuex中。
每次路由跳转,就判断localStorage中是否有token如果没有就跳转到登陆页面。main.js
全局注册 导入/导出 组件
引入importUpload,exportUpload
Vue.component(‘i-import’,importUpload)
Vue.component(‘e-import’,exportUpload)
引入config文件
Vue.prototype.$ config = config
这样方便在各组件中直接通过this.$ config来读取config中的配置值常见错误码
404:页面请求路径出错
500:一般是后台服务未启动,接口问题
405:请求方式不一致,把get改成post,或者把post改成get
400:请求参数不对
415:请求格式不对,form表单形式切换为json形式
502:错误网关
504:网关超时
2 开头一般是请求成功,表示后端成功处理了请求并返回了结果.
3 开头一般是请求重定向,表示要完成请求需要进一步操作.
4 开头一般是请求错误.
5 开头一般是服务器错误.
参考: https://blog.csdn.net/fsfsdgsdg/article/details/121879417
Vue2知识点 - RT相关推荐
- vue2知识点:数据代理
文章目录 一.何为数据代理 二.vue中的数据代理 三.回顾Object.defineProperty() 本人其他相关文章链接 一.何为数据代理 数据代理:通过一个对象代理对另一个对象中属性的操作( ...
- vue2知识点:组件的props属性、非props属性、props属性校验
文章目录 3.10props属性 举例:父组件给子组件传递属性msg和greetText,子组件用属性a和b接收,并打印输出 3.11props校验 举例 3.12非props属性 举例:定义子组件设 ...
- vue2知识点:浏览器本地缓存
文章目录 3.21浏览器本地缓存 3.21.1localStorage 举例:写一个简单的针对本地存储增删改查的案例 3.21.2sessionStorage方法同localStorage一样 本人其 ...
- 【Vue】Vue2知识点总结
Vue知识点总结 Vue的基础概念 Vue是什么 什么是渐进式和框架 什么是MVVM框架 脚手架的使用 全局安装脚手架/包 查看版本 创建项目 进入项目根目录 运行项目 style中开启less功能 ...
- 【vue框架】vue2 知识点整理
脚手架文件结构 ├── node_modules ├── public │ ├── favicon.ico: 页签图标 │ └── index.html: 主页面 ├── src │ ├── asse ...
- vue2知识点:vue-cli脚手架配置代理服务器
文章目录 6.3vue-cli脚手架配置代理服务器 6.3.1解决跨域问题:配置代理_方式1 案例:开2台模拟服务器,模拟客户端端口8080调用2台服务器端口叫5000和5001,实现ajax解决跨域 ...
- Vue2知识点(四)(使用Vue CLI知识点(续集))
1.组件中的自定义事件 1.一种组件通信方式:子组件==>父组件 2.使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调函数在A中) 3.绑定自定义事 ...
- vue 3.0 正式版_一个亲历了vue1.x到3.0的魔幻男人
今天凌晨,00:45,尤小右更新了一条微博: 截止到目前,这条微博下面的留言已经多达136条,满屏焦虑,直呼学不动了... 前端届的菜鸟们纷纷献上膝盖,别更新了,学不动了.jpg搞前端开发N年的老鸟们 ...
- vue组件通信案例练习(包含:父子组件通信及平行组件通信)
文章目录 一.案例概述 二.代码 准备工作: 案例1.1:父组件向子组件传值(或者叫:子组件使用父组件属性),采用v-bind方式实现 案例1.2:子组件向父组件传值(或者叫:子组件调用父组件方法), ...
最新文章
- 一种清除windows通知区域“僵尸”图标的方案——Windows7系统解决方案
- 『Tarjan算法 无向图的双联通分量』
- 用聪明的方式学习Vim,不再死记硬背,复杂命令一学就会 | GitHub 2200星
- Leetcode 200 岛屿数量 (每日一题 20210720)
- Cadence Allegro PCB 铺铜(覆铜)Shape呈格点状填充而不是完整全铜显示问题–Allegro技巧...
- android震动服务能设置时长么,Android实现手机振动设置的方法
- 一个简单的mysql服务检测启动脚本
- oracle排序字符,Oracle数据字符集和排序的用法
- fasthttp中的协程池实现
- 双击 计算机 网络打不开,windows7系统双击“双击计算机”打不开怎么回事
- 微信公众号扫码登录(一)—— 获取微信公众号二维码
- ExpandableListView购物车
- android虚拟机启动失败
- AW349 黑暗城堡
- 掌握销售谈判三大策略,开单成功率提升60%!
- Apache Flink_JZZ_MBY
- 集合竞价如何买入_股票买入技巧:如何进行集合竞价?
- python输入输入:input、map
- 【我是初学者】关于获取配置文件.properties的常见三种方式--只是常见的方式,欢迎牛神来加瓦
- oracle grant execute function,oracle grant 详解