<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>记录</title>
</head>
<body>
</body>
</html>
<script>
//Vue Mixin
//.extend
//asnsyn
//margin 外边距重叠解决办法
//今日集成axios
//加密解密
// 跨域
ajax 四部曲
function ajax(url, callback){
let xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.send();
xhr.onload = function(){
if(this.status == 200){
callback(JSON.parse(this.response))
}else{
throw new Error("加载失败")
}
}
}
//http/https和网络相关知识
//DataV 组件库基于Vue (React版) ,主要用于构建大屏(全屏)数据展示页面即数据可视化,具有多种类型组件可供使用:
vue-router router-view 嵌套问题
// 原型链
// 访问一个对象的属性时, 如果从这个对象里找不到, 就从obj.__proto__里找, 再找不到就继续从obj.__proto__.__proto__里找, 最终会到达Object.prototype
// js中每个对象都有一个_proto_属性指向这个对象构造函数的prototype对象,这个prototype对象也有一个_proto_属性,因此跟链条一样子子孙孙无穷尽也~当然他们的根是null
// 当试图查找一个对象的某个属性时,不仅仅会在对象上查找,还会查找对象的原型,以及对象原型上的原型,层层向上,直到查找到第一个名称相同的属性或者到达一个空的原型,这个就是javascript的原型链机制。其中每一层的原型所构成的这条查找链就是原型链。
// 既然 Object.prototype.__proto__ === null, 那么访问对象的不可达属性时,为什么是undefined 而不是报错 Cannot read property 'name' of null呢?
// 你访问的对象是存在的,在访问属性的时候,如果对象本身不存在这个属性,会往上找原型链上存不存在。最后不管找不着得到,只是属性不存在,而非访问了null的一个属性,所以不会报错。
//更改原型
// Object.setPrototypeOf(friend, dog);
// console.log(friend.getGreeting()); // "Wang"
// console.log(Object.getPrototypeOf(friend) === dog); /
// 1.apply call bind
//apply:方法能劫持另外一个对象的方法,继承另外一个对象的属性为自己所用.参数是两个
// call参数不同 ,参数是列表
// 1、都是用来改变函数的this对象的指向的。
// 2、第一个参数都是this要指向的对象。
// 3、都可以利用后续参数传参。
// apply,call,bind三者的区别?
// 三者都可以改变函数的this对象指向。
// 三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefined或null,则默认指向全局window。
// 三者都可以传参,但是apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入。
// bind 是返回绑定this之后的函数,便于稍后调用;apply 、call 则是立即执行 。
// var person = {
// fullName: function() {
// return this.firstName + " " + this.lastName;
// }
// }
// var person1 = {
// firstName: "Bill",
// lastName: "Gates",
// }
// let aa = person.fullName. (person1); // 将返回 "Bill Gates"
// console.log(aa,'aa')
// 求数组中的最大值:
// var arr=[1,10,5,8,3];
// console.log(Math.max.apply(null, arr)); //10 apply 妙用 : 可以将一个数组默认的转换为一个参数列表
// 常见面试题有: 1、手写bind函数
// Function.prototype.mybind = function (ctx, ...args) {
// const fn = this;
// return function () {
// fn.apply(ctx, args);
// };
// };
// function foo(x, y) {
// console.log(this, x, y);
// }
// const foo1 = foo.mybind({ name: "zhangsan" }, 10, 20);
// foo1();
// 2、new 操作符调用构造函数,具体做了什么?
// 1)创建一个新的对象;
// 2)将构造函数的 this 指向这个新对象;
// 3)为这个对象添加属性、方法等;
// 4)最终返回新对象。
// js中的函数也是对象 (即 (function(){}) instanceof Object == true)
// 所有的对象都有自己的构筑函数
// 所有的函数都能当作构筑函数, 每个函数都有一个prototype属性
// 每个对象都有一个隐藏的o.__proto__属性指向它的构筑函数的prototype
// 于是所有的函数的原型都是Function.prototype (即 (function(){}).__proto__ === Function.prototype)
// 访问一个对象的属性时, 如果从这个对象里找不到, 就从obj.__proto__里找, 再找不到就继续从obj.__proto__.__proto__里找, 最终会到达Object.prototype
var arr1=new Array("1","2","3");
var arr2=new Array("4","5","6");
let bb = Array.prototype.push.apply(arr1,arr2);
console.log(bb,'bb')
// Object.prototype.toString.call
// isNaN —— 检查值是否不是一个普通数字或者是否不能转换为一个普通数字。
// Number.isNaN —— 检查值是否为 NaN。
//------------- display:inline-block的间隙问题和解决办法
// 1) block水平的元素inline-block后,IE6/7没有换行符间隙问题,其他浏览器均有,
// 2)inline水平的元素 inline-block后,所有主流浏览器都换行符 空格间隙问题。
// 3)解决方法:
// ①移除标签间的空格。(代码不优雅)
// ②在父元素上加上font-size:0;以及 letter-spacing 为负值
// -----------------七种JS数据类型 六种基本类型:string、number、boolean、null、undefined、symbol(ES6新增)
// 一种引用数据类型:object、array、function
// symbol函数前不能使用new关键字,否则会报错,这是因为symbol是原始数据类型,而不是对象,所以不能添加属性。
// symbol可以接受一个字符串作为参数,表示对Symbol的描述,主要是在控制台显示时容易区分
// 这个参数可以不加,如果不加在控制台输出就是两个Symbol()不利于区分,加上参数就是为了加以区分。
// Symbol不能与其他值进行运算,否则会报错
// Symbol是唯一的与谁都不相等
// Symbole 可以显示的转为字符串,布尔值,但是不能转为数字,转为数字会报错
// 由于每一个Symbol都不相同,那么可以作为标识符作为对象的属性名,保证不会出现同名的的属性
// Symbol值作为对象的属性名时不能使用点运算符,同理,在对象的内部使用Symbol值时也必须放在方括号中
// var mySymbol = Symbol();
// 1)set集合 :是Object里面的一种, set与数组不同在于set中不可以有重复数据,常用语去重操作
// 2)Map类型:可以允许任何类型作为对象的键,弥补了object只能使用字符串作为键的问题
//判断js数据类型的方法
// 1、typeof typeof('abc') //string
// 可以识别原始类型(Null除外),Null类型会被识别成object
// 不能识别具体的对象类型(Function除外) 能识别函数(function)不能识别数组(Array),数组会识别成(object),
// 2、instanceof
// instanceof 用于判断一个变量是否某个对象的实例(一个实例是否属于某一类型),用来识别对象类型。
// 或者说,对象与构造函数在原型链上是否有关系。
// -----可以判别所有对象类型,包括内置对象和自定义对象
// ------不能判别原始类型
// var a=new Array();
// console.log(a instanceof Array); //true
// console.log(a instanceof Object);//true.(因为Array是object的子类)
// 3、Constructor 查看对象的构造函数,获取的是构造函数
//判别原始类型
// console.log('moon'.constructor === String); //true
// console.log((1).constructor === Number); //true,注意这里1要加上括号
// console.log(true.constructor === Boolean); //true
// //判别内置对象
// console.log([].constructor === Array ); //true
// //判别自定义对象
// function Aaa(){
// }
// var a1 = new Aaa();
// console.log( a1.constructor ); //Aaa
// --------判别原始类型(Undefined和Null除外,因为它们没有构造函数)
// 判别内置对象类型
// 判别自定义对象类型
// -------------此函数对 对象的构造函数进行格式化
// function getConstructorName(obj){
// return (obj===undefined||obj===null)? obj: (obj.constructor&&obj.constructor.toString().match(/functions*([^(]*)/)[1]);
// }
// 4、Object.prototype.toString.call()或{}.prototype.toString.call()
// 在使用时Object.prototype.toString.call(xxx)会返回类似[object String]的字符串给我们,用它就可以很好的判断类型了。
//先把方法封装成一个函数
// function type(obj) {
// return Object.prototype.toString.call(obj).slice(8,-1);
// }
// //字符串截取我们需要的部分
// console.log(type('moon')); //String
// console.log(type(1)); //Number
// console.log(type(true)); //Boolean
// console.log(type(undefined)); //Undefined
// console.log(type(null)); //Null
// console.log(type({})); //Object
// console.log(type([])); //Array
// console.log(type(new Date())); //Date
// console.log(type(/d/)); //RegExp
// console.log(type(function () {})); //Function
// function Person() {
// }
// console.log(type(new Person())); //Object
// -------------- 8、js中的 async 和 defer 有什么区别
// 1)没有这个两个属性时,浏览器遇到script时,文档解析停止,其他线程现在下载并执行js脚本,执行完后接续解析文档
// 2)添加async 时,文档解析不会停止,其他线程下载js脚本,脚本下载完成后开始执行脚本,执行脚本时文档停止解析,直到脚本解析完成,再继续解析 (异步下载,并立即执行)
// 3)添加defer时,文档的解析不会停止,其他线程下载脚本,待文档解析完成之后,脚本才会执行。 (一步下载,待文档解析完成后,执行)
//-------------- !!
// 双叹号 !! 是将表达式强制转化为bool值的运算,运算结果为true或false,表达式是什么值,结果就是对应的bool值,不再取非
// -------------------vue双向绑定原理?
// vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
// Object.defineProperty(data, key, config) 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
// var Book = {}
// var name = '';
// Object.defineProperty(Book, 'name', {
// set: function (value) {
// name = value;
// console.log('你取了一个书名叫做' + value);
// },
// get: function () {
// return '《' + name + '》'
// }
// })
// Book.name = 'vue权威指南'; // 你取了一个书名叫做vue权威指南
// console.log(Book.name); // 《vue权威指南》
//---------------------- Object.create(null) 和 {} 创建对象的区别
// Object.create(proto,[propertiesObject])
// proto:新创建对象的原型对象
// propertiesObject:可选。要添加到新对象的可枚举(新添加的属性是其自身的属性,而不是其原型链上的属性)的属性。
// const car = {
// isSportsCar: false,
// introduction: function () {
// console.log(`Hi girl, this is a ${this.name}.
// Do you like to have a drink with me ? ${this.isSportsCar}`);
// }
// };
// const porsche = Object.create(car,{
// //color成为porsche的数据属性
// //颜色不喜欢,可以改色或贴膜,所以可修改
// color:{
// writable:true,
// configurable:true,
// value:'yellow'
// },
// //type成为porsche的访问器属性
// type:{
// // writable、configurable等属性,不显式设置则默认为false
// // 想把普通车改成敞篷,成本有点大了,所以就设成不可配置吧
// get:function(){return 'convertible'},
// set:function(value){"change this car to",value}
// }
// });
// Object.create(null)会创建一个纯净的对象,原型链上没有任何属性,也就是没有继承Object的任何东西,此时如果我们调用o.toString()会报Uncaught TypeError的错误。
// 另一个使用create(null)的理由是,在我们使用for..in循环的时候会遍历对象原型链上的属性,使用create(null)就不必再对属性进行检查了,当然,我们也可以直接使用Object.keys[]。
// 总结:
// 你需要一个非常干净且高度可定制的对象当作数据字典的时候;
// 想节省hasOwnProperty带来的一丢丢性能损失并且可以偷懒少些一点代码的时候用Object.create(null)吧!其他时候,请用{}。
// Object.create方法的第二个参数添加的对象属性,如果不显式声明,默认是不可遍历的,因为p的属性描述对象的enumerable默认是false,Object.values不会返回这个属性。
// const obj = Object.create({},{p:{
// value : 10,
// enumerable : true,
// configurable : true,
// writable : true,
// }})
// console.log(Object.values(obj)); //[10]
//-------------- Object.keys(obj),Object.values(),Object.entries(obj1) 返回对象自身的(不含继承的)所有可遍历(enumerable)属性的键、值、键值对数组 (只可遍历一级)
// 要返回其枚举自身属性的对象,属于自身的属性,不包含原型对象上的属性
// 常用技巧
// let person = {name:"张三",age:25,address:"深圳",getName:function(){}} //["name", "age", "address", "getName"]
// Object.keys(person).map((key)=>{
// person[key] // 获取到属性对应的值,做一些处理
// })
// Object.values()和Object.keys()是相反的操作,把一个对象的值转换为数组
// Object.entries(obj1) Object.entries方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组(只可遍历一级)
// function test(){
// this.name='zhang';
// this.age ='18'
// };
// var test1 = new test()
// test.prototype.sex = '男'
// console.log(test1.__proto__,'test1__proto__')//对象有的的__proto__属性
// console.log(test.prototype,'test1')//只有构造函数才有prototype属性
//Object.assign(target, ...sources) 方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。它将返回目标对象。
// 如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性。
// 方法只会拷贝源对象自身的并且可枚举的属性到目标对象。
//复制一个对象
const obj = { a: 1 };
const copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
// 数组方法
// 一、不修改原数组
~ slice: 返回一个新的数组对象,这一对象是由begin和end决定的原数组的浅拷贝(包括begin,不包括end)。原始数组不会改变。
~ concat:合并两个或多个数组,返回新的数组。
~ forEach : 对数组的每个元素执行一次给定的函数。
~ map: 创建一个新数组,其结果是该数组中的每个元素调用一次提供的函数的返回值。
~ every: 测试一个数组内的所有元素是否能通过某个指定函数的测试。返回一布尔值。
~ some :测试一个数组内是不是至少有1个元素通过了被提供函数的测试。返回一个布尔值
~ filter: 创建一个新数组,其包含通过所提供函数实现的测试的所有元素
~ reduce: 对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值
~ reduceRight: 接受一个函数作为累加器(从右到左)
~ keys: 返回一个包含数组中每个索引的数组
~ values:返回一个新的数组,该数组包含每个索引的值
~ entries: 返回一个数组,该数组包含原数组的键值对,二维数组
~ indexOf:返回在数组中可以找到一个给定元素的第一个索引,如果不存在则返回-1。
~ lastIndexOf:返回指定元素,在数组中的最后一个索引,如果不存在则返回-1,从后往前查。
~ of: 创建数组Array.of('aa',1,'bb'); 创建一个具有可变数量参数的新数组示例,而不考虑参数的数量或类型。
~ join:将一个数组(或者一个类数组对象)的所有元素连接成一个字符串,并返回
~ includes:用来判断一个数组是否包含一个指定的值,包含返回true,否则返回false string.includes(searchvalue, start)
~ find:返回数组中满足提供的测试函数的第一个元素的值,否则返回undefined
~ findIndex:返回数组中满足提供的测试函数的第一个元素的索引。
~ flat 按照一个可指定的深度遍历的数组,并将所有元素与遍历到的子数组的元素合并为一个
//let aa = [1, 2, [3, 4]].flat()
// [1, 2, 3, 4]
// flat()默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1
// 如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。
// [1, [2, [3]]].flat(Infinity)
// [1, 2, 3]
~ flatMap() 方法对原数组的每个成员执行一个函数,相当于执行Array.prototype.map(),然后对返回值组成的数组执行flat()方法。该方法返回一个新数组,不改变原数组。
// 相当于 [[2, 4], [3, 6], [4, 8]].flat()
// [2, 3, 4].flatMap((x) => [x, x * 2])
// flatMap()只能展开一层数组。
// 二、修改原数组
~ splice:通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。
arrayObject.splice(index,howmany,item1,.....,itemX) 起始,删除数量,添加项目
~ pop:从数组末尾删除一个或多个元素。
~ push:从数组末尾追加一个元素。
~ shift:删除数组第一个元素
~ unshift:将一个或多个元素添加到数组的开头
~ sort :对数组元素进行排序。默认排序顺序是根据字符串UniCode码。因为排序是按照字符串UniCode码的顺序进行排序的,所以首先应该把数组元素都转化成字符串(如有必要),以便进行比较。
// 升序排列
arr.sort(function(a,b){
return a-b
})
// 降序排列
arr.sort(function(a,b){
return b-a
})
// 闭包
// 递归
// 移动端px2rem转换
//mvc、mvvm
//浏览器的基本原理
//前端性能优化
//margin重叠 ,解决方法:当让两个box,处在不同的BFC的时候,margin就不回重叠
重排: 当页面中的HTML结构发生改变(增加、删除元素、位置发生改变等等),只要结构发生改变,浏览器都需要从新的计算一遍最新的dom结构,从新的对当前的页面进行渲染
重绘: 当元素的背景、透明度、颜色发生变化,那么浏览器会对元素进行重新描绘;这个过程就是浏览器的重绘;
『重绘』不一定会出现『重排』,『重排』必然会出现『重绘』
任何改变用来构建渲染树的信息都会导致一次重排或重绘:
1、添加、删除、更新DOM节点
2、通过display: none隐藏一个DOM节点-触发重排和重绘
3、通过visibility: hidden隐藏一个DOM节点-只触发重绘,因为没有几何变化
4、移动或者给页面中的DOM节点添加动画
5、添加一个样式表,调整样式属性
6、用户行为,例如调整窗口大小,改变字号,或者滚动。
3.如何避免重绘或者重排?
1、集中改变样式
我们往往通过改变class的方式来集中改变样式
2、使用DocumentFragment
我们可以通过createDocumentFragment创建一个游离于DOM树之外的节点,然后在此节点上批量操作,最后插入DOM树中,因此只触发一次重排
、、任务队列,定时器任务轮询,任务队列中的任务排序
、、主线程执行完成,开始轮询任务队列,主线程中的全局数据,任务队列可以使用
、、微任务(为主),宏任务(滞后)
、、js执行顺序 ,同步--->异步(微任务--->宏任务)
// ES6--
// promise 产生微任务 JavaScript事件轮询中的宏任务和微任务
、、pending 准备阶段
、、resolved 成功状态
、、rejected 拒绝状态
new Promise((resolve,reject)=>{
resolve('操作成功')
// reject('操作失败')
}).then((val) => {
console.log(val)
},
// err => console.log(err)
).catch((err)=>{
console.log(err)
}).finally(()=>{
console.log('永远会执行。')
})
、、状态产生后是不可逆的
、、Promise中的.then()也是一个Promise
、、后面的.then()是对前面Promise返回结果的一个处理
// Promise.resolve() 等价于Promise.hd
Promise.hd = function(value){
return new Promise(resolve=>{
resolve(value)
})
}
// Promise.reject()
//批量处理Promise.all()
Promise.all([promise1,promise2]).then(results=>{
console.log(results)//1和2的返回值,1和2的状态必须是已解决的情况下才可以
})
//Promise.allSettled()
Promise.allSettled([p1,p2]).then(results=>{
console.log(resulets) //p1和p2无论成功和失败都能返回
})
//Promise.race()
Promise.race([p1,p2]).then(res=>{
console.log(res); //p1和p2谁处理的快,返回谁
})
// ...
// function People(x,y){
// this.x = x;
// this.y = y;
// }
// People.prototype.say=function(){
// console.log('我会说话')。
// }
// let p1 = new People()
// p1.say()
People.prototype={
constructor:People, //如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
sing:function(){},
say:function(){},
}
class People{
constructor(x, y){
this.x = x;
this.y = y;
}
say(){
console.log('我会说话。')
}
}
let p1 = new People()
p1.say()
//继承
class Father{
constructor(x, y){
this.x = x;
this.y = y;
}
sum(){
return this.x+this.y
}
}
class Son extends Father{
constructor(x, y){
super(x, y)
this.x = x;
this.y = y
}
sum(){
super.sum()
}
}
ES5
~小程序生命周期
~应用声明周期
(1)onLaunch: 初始化小程序时触发,全局只触发一次
(2)onShow: 小程序初始化完成或用户从后台切换到前台显示时触发
(3)onHide: 用户从前台切换到后台隐藏时触发
(4)onError: 小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
~页面生命周期
(1)onLoad:首次进入页面加载时触发,可以在 onLoad 的参数中获取打开当前页面路径中的参数。
(2)onShow:加载完成后、后台切到前台或重新进入页面时触发
(3)onReady:页面首次渲染完成时触发
(4)onHide:从前台切到后台或进入其他页面触发
(5)onUnload:页面卸载时触发
触发顺序
后台进入前台先app内应用生命周期——>页面生命周期
前台切换到后台时先page内声明周期->app内应用生命周期
navigateTo, redirectTo 只能打开非 tabBar 页面。
switchTab 只能打开 tabBar 页面。
reLaunch 可以打开任意页面。
页面底部的 tabBar 由页面决定,即只要是定义为 tabBar 的页面,底部都有 tabBar。
调用页面路由带的参数可以在目标页面的onLoad中获取。
1、wx.switchTab(Object object):跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
2、wx.reLaunch(Object object) :关闭所有页面,打开到应用内的某个页面 在小程序插件中使用时,只能在当前插件的页面中调用
3、wx.redirectTo(Object object) :关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面。 在小程序插件中使用时,只能在当前插件的页面中调用
4、wx.navigateTo(Object object) :保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层。在小程序插件中使用时,只能在当前插件的页面中调用
5、wx.navigateBack(Object object):关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层。 在小程序插件中使用时,只能在当前插件的页面中调用
事件绑定
<view bindtap="handleTap"> Click here! </view>
除 bind 外,也可以用 catch 来绑定事件。与 bind 不同, catch 会阻止事件向上冒泡。
<view id="middle" catchtap="handleTap2">Click here! </view>
mut-bind 来绑定事件。一个 mut-bind 触发后,如果事件冒泡到其他节点上,其他节点上的 mut-bind 绑定函数不会被触发,但 bind 绑定函数和 catch 绑定函数依旧会被触发。
小程序分包
├── app.js
├── app.json
├── app.wxss
├── packageA
│ └── pages
│ ├── cat
│ └── dog
├── packageB
│ └── pages
│ ├── apple
│ └── banana
├── pages
│ ├── index
│ └── logs
└── utils
打包原则
1、声明 subpackages 后,将按 subpackages 配置路径进行打包,subpackages 配置路径外的目录将被打包到 app(主包) 中
2、app(主包)也可以有自己的 pages(即最外层的 pages 字段)
3、subpackage 的根目录不能是另外一个 subpackage 内的子目录
4、tabBar 页面必须在 app(主包)内
引用原则:
1、packageA 无法 require packageB JS 文件,但可以 require app、自己 package 内的 JS 文件
2、packageA 无法 import packageB 的 template,但可以 require app、自己 package 内的 template
3、packageA 无法使用 packageB 的资源,但可以使用 app、自己 package 内的资源
小程序独立分包:
独立分包是小程序中一种特殊类型的分包,可以独立于主包和其他分包运行。从独立分包中页面进入小程序时,不需要下载主包。当用户进入普通分包或主包内页面时,主包才会被下载。
开发者可以按需将某些具有一定功能独立性的页面配置到独立分包中。当小程序从普通的分包页面启动时,需要首先下载主包;而独立分包不依赖主包即可运行,可以很大程度上提升分包页面的启动速度。
一个小程序中可以有多个独立分包。
限制:
1、独立分包属于分包的一种。普通分包的所有限制都对独立分包有效。独立分包中插件、自定义组件的处理方式同普通分包。
2、独立分包中不能依赖主包和其他分包中的内容,包括js文件、template、wxss、自定义组件、插件等。主包中的app.wxss对独立分包无效,应避免在独立分包页面中使用 app.wxss 中的样式; App 只能在主包内定义,独立分包中不能定义 App,会造成无法预期的行为; 独立分包中暂时不支持使用插件。
分包预下载
1、开发者可以通过配置,在进入小程序某个页面时,由框架自动预下载可能需要的分包,提升进入后续分包页面时的启动速度。对于独立分包,也可以预下载主包。
2、分包预下载目前只支持通过配置方式使用,暂不支持通过调用API完成。
3、预下载分包行为在进入某个页面时触发,通过在 app.json 增加 preloadRule配置来控制。
小程序框架搭建
小程序面试题
Vue
执行顺序如下:
父组件 created
子组件 created
子组件 mounted
父组件 mounted
如果有多个子组件:
父组件created钩子结束后,依次执行子组件的created钩子
多个子组件的created执行顺序为父组件内子组件DOM顺序
多个子组件的mounted顺序无法保证,跟子组件本身复杂程度有关
父组件一定在所有子组件结束mounted钩子之后,才会进入mounted钩子
Vue3
1、压缩包体积更小
2、Object.defineProperty -> Proxy
Object.defineProperty 缺点:
1)无法监听ES6的 Set、Map 变化
2)无法监听 Class 类型的数据
3)属性的新增和删除也无法监听
4)数组元素的增加和删除也无法监听
3、创建实例改为了函数调用
import Vue from 'vue'
new Vue({
router,
render: h => h(App),
}).$mount('#app')
改为:
import { createApp } from 'vue'
createApp(App).use(store).use(router).mount('#app')
import { createStore } from 'vuex'
export default createStore({
state: {
},
mutations: {
},
actions: {
},
modules: {
}
})
import Router from 'vue-router'
const router = new Router({
routes,
})
改为:
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
4、 Vue3.x 生命周期变化
被替换:
beforeCreate -> setup()
created -> setup()
重命名:
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
errorCaptured -> onErrorCaptured
新增的:
新增的如下2个方便调试 debug 的回调钩子:api
onRenderTracked
onRenderTriggered
setup() 页面创建之前执行的函数。所以整个面用setup()函数来初始化参数
import {reactive,toRefs} from "vue"
export default {
name: "Home",
setup() {
const fromData = reactive({
userName:'admin',
password:'123456'
})
const data = toRefs(fromData);
return {
...data
}
}
};
Vue3.x 生命周期在调用前需要先进行引入import { reactive, toRefs, onMounted, onBeforeMount, onBeforeUpdate, onUpdated, } from "vue";
setup() {
const id = ref(1)
console.log('setup')
onBeforeMount(() => {
console.log('onBeforeMount')
})
onMounted(() => {
console.log('onMounted')
})
onBeforeUpdate(() => {
console.log('onBeforeUpdate')
})
onUpdated(() => {
console.log('onUpdated')
})
onBeforeUnmount(() => {
console.log('onBeforeUnmount')
})
onUnmounted(() => {
console.log('onUnmounted')
})
// 测试 update 相关钩子
setTimeout(() => {
id.value = 2
}, 2000)
return {
id
}
},
取消了 this,取而代之的是 setup 增长了2个参数:
props,组件参数
context,上下文信息
5、reactive 方法
被 reactive 方法包裹后的 对象 就变成了一个代理对象
import { reactive } from 'vue'
setup() {
// 普通对象
const obj1 = {
cnt: 1
}
// 代理对象
const obj2 = reactive({
cnt: 1
})
obj1.cnt++
obj2.cnt++
return {
obj1,
obj2
}
}
//1、 2 普通对象属性更新时,页面是不会同步更新的。只有代理对象,才能够实现双向绑定。
6、 ref 方法
被 ref 方法包裹后的 元素 就变成了一个代理对象。
setup() {
const count = ref(100)
}
setup() {
const count = reactive({
value: 100
})
}
由于变成了一个代理对象,因此取值的时候须要 .value:
setup() {
const count = ref(100)
console.log(count.value) // output: 100
}
另外 ref 的结果在 template 上使用时,会自动打开 unwrap,不须要再加 .value
<template>
<div>{{ count }}</div>
</template>
<script>
export default {
setup() {
return {
count: ref(0)
}
}
}
</script>
7、isRef 方法
判断一个对象是否 ref 代理对象。
const unwrapped = isRef(foo) ? foo.value : foo
toRefs 方法 将一个 reactive 代理对象打平,转换为 ref 代理对象,使得对象的属性能够直接在 template 上使用。
8、template模板中允许使用多个子标签