1.vue2和vue3的diff算法区别
vue2 diff算法就是进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方,最后用patch记录的消息去局部更新Dom。 vue2 diff算法会比较每一个vnode,而对于一些不参与更新的元素,进行比较是有点消耗性能的。
vue2中使用 Object.defineProperty() 拦截对象属性改变,需要递归为每个属性添加 getter 和 setter。vue3使用 Proxy 可以直接监听对象而非属性。
- vue3使用 Patch flags 优化虚拟DOM diff。
vue3在虚拟节点上新增 Patch flags 属性,标记是否需要对比 children 和 props,避免不必要的深层次递归对比,提高 diff 速度。
- vue3支持 block tree diff 算法。
vue2只能 node 对 node 对比,vue3可以通过标记,一次比较多个同类节点,减少递归次数,提高性能。
vue3 diff算法在初始化的时候会给每个虚拟节点添加一个patchFlags,patchFlags就是优化的标识。 只会比较patchFlags发生变化的vnode,进行更新视图,对于没有变化的元素做静态标记,在渲染的时候直接复用。
2.vue的this.$nextTick原理
官网说法:
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
本质是对 JavaScript 执行原理EventLoop的一种应用。EventLoop其实就是事件循环。nextTick 的核心是利用了如 Promise 、MutationObserver、setImmediate、setTimeout的原生 JavaScript 方法来模拟对应的微/宏任务的实现,本质是为了利用 JavaScript 的这些异步回调任务队列来实现 Vue 框架中自己的异步回调队列
- $nextTick 把一个回调函数推送到微任务队列中。
$nextTick方法会返回一个Promise,并且会把传入的回调函数加入微任务队列,在DOM更新完成后执行。
- Vue的更新机制是异步执行的。
Vue的数据更新触发setter,会标记组件为“脏”,但不会立即执行DOM更新。只有等同一事件循环中的其他代码执行完,Vue才会刷新队列中标记“脏”的组件。
所以$nextTick的回调函数可以确保在DOM更新完成后执行。
具体原理是:
- Vue监听数据变化,开启一个队列,缓存所有数据变更后的组件。
- 在同一事件循环中,等其他代码执行完,刷新队列,执行DOM更新。
- $nextTick会把回调推迟到微任务队列,在DOM更新后执行。
- 所以回调函数可以拿到更新后的DOM状态。
简单来说,$nextTick利用了Vue的异步队列更新机制和微任务的执行时机,确保回调函数在DOM更新后执行,从而可以获取更新后的DOM
为什么要用nextTick?
DOM更新:
首先,我们要知道:Vue实现响应式并不是数据发生变化之后DOM立即变化,而是异步执行DOM更新的
<template>
<div class="test">
<div>
<button @click="test" ref="btn">{{ msg }}</button>
</div>
</div>
</template>
<script>
export default {
data () {
return {
msg: '按钮'
}
},
methods: {
test () {
this.msg = '信息改变了。。。。'
console.log('打印结果:' + this.$refs.btn.innerText) // 打印结果:按钮
}
}
}
</script>
此时log结果是:打印结果:‘按钮‘。而不是后来的 ‘信息改变了。。。。’ 原因:Vue的响应式是异步执行DOM更新。
异步执行DOM更新
Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。
vue在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成以后,再进行视图更新.
如果是同步更新,则多次对一个或多个属性赋值,会频繁触发 UI/DOM 的渲染,所以,用异步更新可以减少一些无用渲染,提高性能
同时由于 VirtualDOM 的引入,每一次状态发生变化后,状态变化的信号会发送给组件,组件内部使用 VirtualDOM 进行计算得出需要更新的具体的 DOM 节点,然后对 DOM 进行更新操作,每次更新状态后的渲染过程需要更多的计算,而这种无用功也将浪费更多的性能,所以异步渲染变得更加至关重要。
什么时候用?
在数据变化后执行的某个操作,而这个操作需要使用随数据变化而变化的DOM结构的时候,这个操作就需要方法在nextTick()的回调函数中
在vue生命周期中,如果在created()钩子进行DOM操作,也一定要放在nextTick()的回调函数中。
因为在created()钩子函数中,页面的DOM还未渲染,这时候也没办法操作DOM,所以,此时如果想要操作DOM,必须将操作的代码放在nextTick()的回调函数中
3.vue2的diff算法
4.keep-alive原理
keep-alive是Vue中内置的一个抽象组件。它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
当keepalive页面缓存下来的时候,如果页面有activated钩子和created钩子函数,这两个函数会被同时触发,可以用activited代替created或者mounted.被缓存的页面跳转到其他页面,或者从当前页面返回上一页,都会触发deactivated
keep-alive是Vue内置的一个组件,可以为被包含的组件保留状态,或避免重新渲染
router-view也是一个组件,如果直接被包在keep-alive里面,所有路径匹配到的视图组件都会被缓存
当keepalive页面缓存,有activated钩子和created钩子函数时
这两个函数会被同时触发,此时应该使用activated代替created,因为created只会触发一次
页面被缓存下来的时候,就不会触发destroyed生命钩子
取而代之触发的是deactivated钩子
属性:
include,exclude,max
<!-- 逗号分隔字符串 -->
<keep-alive include="a,b">
<component :is="view"></component>
</keep-alive>
<!-- 正则表达式 (使用 `v-bind`) -->
<keep-alive :include="/a|b/">
<component :is="view"></component>
</keep-alive>
<!-- 数组 (使用 `v-bind`) -->
<keep-alive :include="['a', 'b']">
<component :is="view"></component>
</keep-alive>
注意:想要缓存的组件一定要给定name属性,并且要和include,exclude给定的值一致
源码:
export default {
name: 'keep-alive',
abstract: true,
props: {
include: [String, RegExp, Array],
exclude: [String, RegExp, Array],
max: [String, Number]
},
created () {
this.cache = Object.create(null)
this.keys = []
},
destroyed () {
for (const key in this.cache) {
pruneCacheEntry(this.cache, key, this.keys)
}
},
mounted () {
this.$watch('include', val => {
pruneCache(this, name => matches(val, name))
})
this.$watch('exclude', val => {
pruneCache(this, name => !matches(val, name))
})
},
render() {
/* 获取默认插槽中的第一个组件节点 */
const slot = this.$slots.default
const vnode = getFirstComponentChild(slot)
/* 获取该组件节点的componentOptions */
const componentOptions = vnode && vnode.componentOptions
if (componentOptions) {
/* 获取该组件节点的名称,优先获取组件的name字段,如果name不存在则获取组件的tag */
const name = getComponentName(componentOptions)
const { include, exclude } = this
/* 如果name不在inlcude中或者存在于exlude中则表示不缓存,直接返回vnode */
if (
(include && (!name || !matches(include, name))) ||
// excluded
(exclude && name && matches(exclude, name))
) {
return vnode
}
const { cache, keys } = this
const key = vnode.key == null
// same constructor may get registered as different local components
// so cid alone is not enough (#3269)
? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
: vnode.key
if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance
// make current key freshest
remove(keys, key)
keys.push(key)
} else {
cache[key] = vnode
keys.push(key)
// prune oldest entry
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
}
vnode.data.keepAlive = true
}
return vnode || (slot && slot[0])
}
}
可以看到,它有3个属性,即有3个props。此外,它有created,destroyed,mounted,render四个钩子。
5.promise
什么是promise
Promise是ES6异步编程的一种解决方案(目前最先进的解决方案是async和await的搭配(ES8),但是它们是基于promise的),从语法上讲,Promise是一个对象或者说是构造函数,用来封装异步操作并可以获取其成功或失败的结果。
为什么要使用promise 最重要也是最主要的一个场景就是ajax和axios请求。通俗来说,由于网速的不同,可能你得到返回值的时间也是不同的,但是我们下一步要执行的代码依赖于上一次请求返回值,这个时候我们就需要等待,结果出来了之后才知道怎么样继续下去。
主要用来优化异步操作,在没有他之前,js中的异步处理主要是利用回调函数,典型的有setTimeout ajax 。现在有了promise,就可以对这些异步操作进行改写了。
基本使用
var p1 = new Promise(function(resolve,reject){
//异步操作 resolve(obj1) 或者 reject(obj2)
});
p1.then(function(rs){
// 如果p1的状态是resolved,则then中的函数
//会执行,且obj1的值会传给rs
}).catch(function(rs){
// 如果p1的状态是reject,则catch中的函数
// 会执行,且obj2的值会传给rs
}).finally(function(){
// 一定会执行的函数
})
三种状态和值
一个Promise对象的状态可能是如下三种之一:pending,resolved,rejected。
这三种状态不受外界影响,而且状态只能从pending改变为resolved或者rejected,并且不可逆
then的格式及其执行逻辑
他接收2个参数,每个参数都是函数,第二个参数是可选的 如下:
p.then(函数1,[,函数2])
两个参数都是函数
let p4 = new Promise((resolve,reject) => {
// resolve('1')
reject('3')
})
p4.then(res => {
console.log('成了',res)
},err => {
console.log('无了',err) //err和catct只会打印一个
}).catch(errs => {
console.log('catch',errs)
})
6.网络协议有哪些层
第一层:物理层
第二层:数据链路层
第三层:网络层
第四层:传输层
第五层:会话层
第六层:表示层
第七层:应用层
7.http协议
8.webwork
9.vue2和vue3的区别
1.双向数据绑定原理不同,vue2是通过objcet.defineProperty()对数据进行劫持结合发布订阅模式来实现的。defineProperty只能监听某个属性,不能对全对象监听。vue3是通过Proxy实现双向绑定。可以监听数组,不再单独的对数组做特异性处理。可以检测到数组内部数据的变化。
2.vue3支持多个根节点
3.composition API。vue2使用的是option API,vue3使用composition API,vue2在代码里面分割了不同的属性,data,methods,computed.vue3 composition API让我们用户方法来分割,使代码更简介。
4.生命周期不同
vue2 --------------- vue3
beforeCreate -> setup()
Created -> setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroyed -> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
5.diff算法不同
vue2
vue2 diff算法就是进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方,最后用patch记录的消息去局部更新Dom。 vue2 diff算法会比较每一个vnode,而对于一些不参与更新的元素,进行比较是有点消耗性能的。
vue3
vue3 diff算法在初始化的时候会给每个虚拟节点添加一个patchFlags,patchFlags就是优化的标识。 只会比较patchFlags发生变化的vnode,进行更新视图,对于没有变化的元素做静态标记,在渲染的时候直接复用
6.v-if和v-for的优先级
vue2
我们最好不要把v-if和v-for同时用在一个元素上,这样会带来性能的浪费(每次都要先渲染才会进行条件判断)
// vue2
v-for 优先于 v-if 生效
<div v-if="index == 1" v-for="(item,index) in arr" :key="index">{{item}}</div>
// vue3
v-if 优先于 v-for 生效
<div v-if="index == 1" v-for="(item,index) in arr" :key="index">{{item}}
</div>
vue中会给我们报警告: 意思就是:属性“index”在渲染期间被访问,但未在实例上定义(v-if先进行判断,
但是这时候v-for还没有渲染,所以index是找不到的)
10.实现sleep函数
async function sleep (time) {
return new Promise(resolve => {
setTimeout(resolve,time)
})
}
async function foo () {
console.log(1)
await sleep(2000)
console.log(2) //2秒后输出2
}
foo()
11.vue 父子组件生命周期执行顺序
挂载阶段 执行顺序为:
父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
更新阶段
执行顺序为: 父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated
销毁阶段
执行顺序为: 父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed
规律就是:父组件先开始执行,然后等到子组件执行完,父组件收尾
12.翻转一个字符串的几种方式
1.字符串转数组,翻转数组,数组转字符串
let str = "hello world";
let newStr = str.split("").reverse().join("");
console.log(newStr);
2.for循环
function reverseString2(str){
var newStr = "";
for(var i=str.length-1; i>=0; i--){
newStr += str[i];
}
return newStr;
}
console.log(reverseString2("helloworld")); //dlrowolleh
13.vite为什么比webpack快
webpack和vite的区别
webpack基于common.js,先打包合并在请求服务器,更改一个模块,其他有依赖关系的模块都会重新打包
vite基于esModule,自动向依赖的module的发请求,服务端按需变异返回,改动一个模块仅仅会重新请求该模块
为什么选vite作为构建工具?
vite服务器启动速度比webpack快,由于vite启动的时候不需要打包,也就无需分析模块依赖、编译,所以启动速度非常快。当浏览器请求需要的模块时,再对模块进行编译,这种按需动态编译的模式,极大缩短了编译时间,当项目越大,文件越多时,vite的开发时优势越明显。vite热更新比webpack快,vite在HRM方面,当某个模块内容改变时,让浏览器去重新请求该模块即可,而不是像webpack重新将该模块的所有依赖重新编译。
webpack开发构建的时候,他会默认构建你的所有页面,抓取整个应用以后提供服务,这就会导致,在你的项目中任何一个地方有一个错误(尽管你当前还未进入这个页面),这都会影响构建速度,因此你的项目越大,webpack构建时间就越长,启动速度就越慢
而对于vite来说,同样的错误,他只有进入到这个页面的时候才会出现错误提示,因为vite并不会在一开始就构建你的项目,而是会把应用分为【依赖】和【源码】,对于源码部分 他会根据【路由】来进行拆分,只构建一开始就必须构建的内容,同时vite以【原生ESM】的方式为浏览器提供源码,让浏览器承担了部分打包的工作,也正是因为这样的机制,不管你的项目有多大,他会先构建一开始必须要构建的内容,因此大大提升了构建的速度
14.哈希路由和history的区别?有什么缺点
两种路由方式都是客户端的路由方式,路径发生变化时,都不会向服务器发起请求,而是通过js监听路径变化,渲染不同内容
原理不同
hash模式的实现原理是通过监听hash change事件来实现的。history模式是通过调用history.pushState或者replaceState并且监听popState事件来实现的。history.pushState会追加历史记录,并更换地址栏信息,但是页面不会刷新,需要手动调用地址变化之后的处理函数,监听popState事件是为了响应浏览器的前进后退功能。
表现不同
hash模式会在地址栏中有#号,而history模式没有;同时由于history模式的实现原理用到H5的新特性,所以它对浏览器的兼容性有要求(IE >= 10)。
history模式特点
history模式开发的SPA项目,需要服务器端做额外的配置,否则会出现刷新白屏(链接分享失效)。原因是页面刷新时,浏览器会向服务器真的发出对这个地址的请求,而这个文件资源又不存在,所以就报404。处理方式就由后端做一个保底映射:所有的请求全部拦截到index.html上。
15.css翻转一个列表 实现1:
display-direction:row-reverse;
16.H5和js怎么通信,jsBridge在什么时候加载的
17.vue3的teleport内置组件
21.无感刷新token
22.vue3如何全局挂载
// 在main.ts中
// 引入 echarts
import * as echarts from "echarts"
// 全局挂载 echarts
app.config.globalProperties.$ECharts = echarts
// 在页面中使用
import { onMounted,getCurrentInstance,ComponentInternalInstance } from "vue"
类型可以为任意类型
const { proxy } = getCurrentInstance() as any
onMounted(() => {
// 获取挂载的组件实例
const echarts = proxy.$ECharts
//初始化挂载
const echarts1 = echarts.init(document.getElementById("myChart"))
//添加配置
echarts1.setOption(option)
// 自适应
window.onresize = function () {
echarts1.resize()
}
})
25.webpack做过哪些优化 webpack优化配置
26.jSON.stringfy什么时候会报错
使用json.stringfy会出现以下问题:
这里边的丢失内容为undefined类型c和函数f,在查询了资料后发现JSON.stringify会丢失的内容有以下内容:
使用JSON.Stringify 转换的数据中,如果包含 function,undefined,Symbol,这几种类型,不可枚举属性,JSON.Stringify序列化后,这个键值对会消失。 转换的数据中包含 NaN,Infinity 值(含-Infinity),JSON序列化后的结果会是null。 转换的数据中包含Date对象,JSON.Stringify序列化之后,会变成字符串。 转换的数据包含RegExp 引用类型序列化之后会变成空对象
29.vue2和vue3区别
vue3中移除过滤器filter,官方推荐,如果要使用过滤器可以使用 computed 计算属性和method 函数来代替。如果是使用了全局过滤器,官方也提供了一个属性来进行迁移修复,但是也只推荐用于迁移。
30.vue3 toRefs toRef reactive的关系
31.一维数组转换成树形结构
let data= [
{ id: 2, name: '部门B', parentId: 0 },
{ id: 3, name: '部门C', parentId: 1 },
{ id: 1, name: '部门A', parentId: 2 },
{ id: 4, name: '部门D', parentId: 1 },
{ id: 5, name: '部门E', parentId: 2 },
{ id: 6, name: '部门F', parentId: 3 },
{ id: 7, name: '部门G', parentId: 2 },
{ id: 8, name: '部门H', parentId: 4 },
{ id: 9, name: '部门I', parentId: 8 }
];
function transTree(data) {
let result = []
let map = {}
if (!Array.isArray(data)) {//验证data是不是数组类型
return []
}
data.forEach(item => {//建立每个数组元素id和该对象的关系
map[item.id] = item //这里可以理解为浅拷贝,共享引用
})
data.forEach(item => {
let parent = map[item.parentId] //找到data中每一项item的爸爸
if (parent) {//说明元素有爸爸,把元素放在爸爸的children下面
(parent.children || (parent.children = [])).push(item)
} else {//说明元素没有爸爸,是根节点,把节点push到最终结果中
result.push(item) //item是对象的引用
}
})
return result //数组里的对象和data是共享的
}
console.log(transTree(data))
32.安卓 ios H5有哪些兼容性
1.时间格式 ios不支持2000-02-02这种格式,只支持2000/01/01这种
2.ios input 调用键盘屏幕上移后,失去焦点不自动回落
解决方案
//js
let myFunction
let isIos = true
if (isIos) { // 既是微信浏览器 又是ios============(因为查到只有在微信环境下,ios手机上才会出现input失去焦点的时候页面被顶起)
document.body.addEventListener('focusin', () => { // 软键盘弹起事件
clearTimeout(myFunction)
})
document.body.addEventListener('focusout', () => { // 软键盘关闭事件
clearTimeout(myFunction)
myFunction = setTimeout(function() {
window.scrollTo({top: 0, left: 0, behavior: 'smooth'})// 重点 =======当键盘收起的时候让页面回到原始位置
}, 200)
})
}
3.ios中input键盘事件keyup、keydown、keypress支持不是很好, 用input监听键盘keyup事件,在安卓手机浏览器中是可以的,但是在ios手机浏览器中用输入法输入之后,并未立刻相应keyup事件,只有在通过删除之后才可以响应
方法:可以用html5的oninput事件去代替keyup
<input type="text" id="testinput">
<script type="text/javascript">
document.getelementbyid('input').addeventlistener('input', function(e){
var value = e.target.value;
});
</script>
ios 设置input 按钮样式会被默认样式覆盖
解决方案:
input,textarea {
border: 0;
-webkit-appearance: none;
}
实现android和ios系统手机打开相机并可选择相册功能
<input class="js_upfile cover1" type="file" name="cover" accept="image/*" capture="camera" multiple/>
$(function () {
//获取浏览器的useragent,并转化为小写
var ua = navigator.useragent.tolowercase();
//判断是否是苹果手机,是则是true
var isios = (ua.indexof('iphone') != -1) || (ua.indexof('ipad') != -1);
if (isios) {
$("input:file").removeattr("capture");
};
})
安卓滚动条问题
Android手机中除了页面本身的那个比较细长的滚动条外还停靠了一个又宽又短的,比较影响美观,可以用一下方法将其隐藏,iOS没有。
html, body {
height: 100%;
overflow: auto;
}
// 下面设置成body也可以,两者只需设置一个即可,但是上面的height必须都设置
html::-webkit-scrollbar {
display: none;
}
ios滑动卡顿问题
当为body设置height: 100%时,页面会卡顿,所以没有特殊情况不要设置height,如果必须设置需要加上:
-webkit-overflow-scrolling: touch;
33.Number和parseInt的区别,Number('a') parseInt('a) 打印出什么
都会打印出NAN
34.vue模板编译原理
35.js垃圾回收机制
主要有2种方法:
标记清除
引用计数
36.webpck基本配置
37.作用域和作用域链
作用域
JavaScript 中的作用域是我们可以有效访问变量或函数的区域。作用域规定了如何查找变量,也就是确定当前执行代码对变量的[访问权限]
JavaScript 有两种类型的作用域:全局作用域、局部作用域。局部作用域又可以分为:函数作用域、块作用域([ES6]
作用域链
一般情况下,变量取值应到创建这个变量的函数的作用域中取值。如果在当前作用域找不到,向上级作用域查找,直到全局作用域,这么一个查找过程形成的链条就叫做作用域链。
38.移动端适配
vw布局,rem布局
39.webpack配置多路由页面
配置多个路由入口文件
微前端
低代码
错误监控
webpack打包原理
webpack的打包原理:首先它会读取项目中的每个文件,然后根据配置文件中的规则,将这些文件编译成一个或多个bundle文件,最后将这些文件输出到指定的文件夹中。
具体来说,webpack会根据配置文件中的配置,对源文件进行编译,在编译的过程中,会将源文件转换为模块,并使用loader处理模块,然后将模块转换为可执行的javascript代码,最后将代码输出到指定的文件夹中。
webpack性能优化方案
compresionWebpackPlugin 开启gzip压缩
promise特点
一旦状态确定就不会变
vite做过哪些优化
微信小程序组件样式怎么使用全局样式
组件样式隔离
默认情况下,自定义组件的样式只受到自定义组件 wxss 的影响。除非以下两种情况:
app.wxss或页面的wxss中使用了标签名选择器(或一些其他特殊选择器)来直接指定样式,这些选择器会影响到页面和全部组件。通常情况下这是不推荐的做法。- 指定特殊的样式隔离选项
styleIsolation。
Component({
options: {
styleIsolation: 'isolated'
}
})
此外,小程序基础库版本 2.2.3 以上支持 addGlobalClass 选项,即在 Component 的 options 中设置 addGlobalClass: true 。 这个选项等价于设置 styleIsolation: apply-shared ,但设置了 styleIsolation 选项后这个选项会失效。
Component({
options: {
addGlobalClass: true,
}
})
怎么单独封装onLoad,onShow,重写page
如果页面加载过慢,会有哪些原因,你怎么查找问题,从哪些方面。比如预加载,骨架屏,从a页面到b页面携带参数
怎么在不满足条件下阻止右上角微信分享
wx.hideShareMenu()
app.js的生命周期和页面的生命周期 onshow和onLoad有阻塞关系吗
如果都是同步代码,app.js的先执行,如果app.js的onshow有异步方法,page的onShow是同步代码,则先执行page的onShow
微信小程序热启动和冷启动
假如用户已经打开过某小程序,然后在一定时间内(五分钟)再次打开该小程序,此时无需重新启动,只需将后台态的小程序切换到前台,这个过程就是热启动;
冷启动指的是用户首次打开或小程序被微信主动销毁后再次打开的情况,此时小程序需要重新加载启动。
微信小程序更新机制
小程序冷启动时如果发现有新版本,将会异步下载新版本的代码包,并同时用客户端本地的包进行启动,即新版本的小程序需要等下一次冷启动才会应用上。 如果需要马上应用最新版本,可以使用 wx.getUpdateManager API 进行处理。
wx.getUpdateManager()使用该接口,可以获知是否有新版本小程序、新版本是否下载好以及应用新版本的能力
// 获取小程序更新机制兼容
if (wx.canIUse('getUpdateManager')) {
const updateManager = wx.getUpdateManager()
updateManager.onCheckForUpdate(function (res) {
// 请求完新版本信息的回调
if (res.hasUpdate) {
updateManager.onUpdateReady(function () {
wx.showModal({
title: '更新提示',
content: '新版本已经准备好,是否重启应用?',
success: function (res) {
if (res.confirm) {
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
updateManager.applyUpdate()
}
}
})
})
updateManager.onUpdateFailed(function () {
// 新的版本下载失败
wx.showModal({
title: '已经有新版本了哟~',
content: '新版本已经上线啦~,请您删除当前小程序,重新搜索打开哟~',
})
})
}
})
} else {
// 如果希望用户在最新版本的客户端上体验您的小程序,可以这样子提示
wx.showModal({
title: '提示',
content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
})
}
40.webpack的plugin 和loader区别
loader运行在打包文件之前(loader为在模块加载时的预处理文件)
plugins在整个编译周期都起作用。
loader
由于webpack只能打包commonjs规范的文件,所以,针对css,图片等格式的文件没法打包,就需要引入第三方的模块进行打包。loader虽然扩展了webpack,但是他只专注于转换文件这一个领域,完成压缩,打包,语言翻译。
loader是运行在node.js中。仅仅是为了打包。仅仅是为了打包。
如: css-loader和style-loader模块是为了打包css的 babel-loader和babel-core模块时为了把ES6的代码转成ES5 url-loader和file-loader是把图片进行打包的
plugin
plugin也是为了扩展webpack的功能,但是plugin是作用于webpack本身上的。
而且plugin不仅只局限在打包,资源的加载上,它的功能要更加丰富。从打包优化和压缩,到重新定义环境变量,功能强大到可以用来处理各种各样的任务。webpack提供了很多开箱即用的插件:CommonChunkPlugin主要用于提取第三方库和公共模块,避免首屏加载的bundle文件,或者按需加载的bundle文件体积过大,导致加载时间过长,是一把优化的利器。而在多页面应用中,更是能够为每个页面间的应用程序共享代码创建bundle。
插件可以携带参数,所以在plugins属性传入new实例。
针对html文件打包和拷贝(还有很多设置)的插件:html-webpack-plugin。
//对html模板进行处理,生成对应的html,引入需要的资源模块
new HtmlWebpackPlugin({
template:'./index.html',//模板文件,即需要打包和拷贝到build目录下的html文件
filename:'index.html',//目标html文件
chunks:['useperson'],//对应加载的资源,即html文件需要引入的js模块
inject:true//资源加入到底部,把模块引入到html文件的底部
})
]```