前言

递归函数简单的定义是:一个自调用函数,这意味着它将在执行的某个时刻调用自己

从理论上讲,递归是一种需要两个属性的行为:

  • 结束点:停止递归的情况
  • 一组规则:负责将所有的操作减少到结束点

如果没有结束点,递归将成为一个无限循环,但是如果一组规则就不能实现期望的行为,所以两者都存在才能使它正常工作。

阅读全文 »

CSS 变量(CSS variable)又叫做”CSS 自定义属性”(CSS custom properties),可以通过 JS 动态改变。

  • var() 函数用于插入 CSS 变量的值。

  • CSS 变量可以访问 DOM,这意味着您可以创建具有局部或全局范围的变量,使用 JavaScript 来修改变量,以及基于媒体查询来修改变量。

  • 使用 CSS 变量的一种好方法涉及设计的颜色。您可以将它们放在变量中,而不必一遍又一遍地复制和粘贴相同的颜色。

var() 函数的语法

var() 函数用于插入 CSS 变量的值。

var() 函数的语法如下:

阅读全文 »

跨域是指在同一网站下,由于浏览器的安全机制,不能直接访问其他网站的数据。而前端开发中,由于业务的需要,经常需要和其他网站进行数据交互。因此,解决跨域问题成为了前端开发必备的技能。

本文将详细介绍跨域的八种实现方式,以及它们的使用场景、优缺点。

JSONP

JSONP 是一种利用 <script> 标签进行跨域请求的方式。它的原理是在请求地址中添加一个回调函数名,服务端在返回数据时会将数据作为参数传入该回调函数中,并返回给客户端。客户端则可以通过定义这个回调函数来处理返回的数据。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function jsonp(url, callback) {
const script = document.createElement("script");
script.src = `${url}&callback=${callback}`;
document.body.appendChild(script);
window[callback] = function (data) {
document.body.removeChild(script);
delete window[callback];
callback(data);
};
}

jsonp("http://example.com/data", function (data) {
console.log(data);
});
阅读全文 »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
function createPoster(val) {
let videoCanList = [],
curDateList = [];
new Promise((reslove, reject) => {
// 在缓存中创建video标签
let video = document.createElement("VIDEO");
// 通过setAttribute给video dom元素添加自动播放的属性,因为视频播放才能获取封面图
video.muted = true;
// 通过setAttribute给video dom元素添加自动播放的属性,因为视频播放才能获取封面图
video.autoplay = true;
//允许跨域访问
video.crossOrigin = "anonymous";
// 上面我们只是创建了video标签,视频播放需要内部的source的标签,scr为播放源
video.innerHTML = "<source src=" + val + ' type="audio/mp4">';
// 再创建canvas画布标签
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
// video注册canplay自动播放事件
//视频的总长度
// video.currentTime = newVideo.duration / 2; // app报错
//视频的总长度
// video.currentTime = newVideo.duration / 2; // app报错
video.addEventListener(
"canplay",
(e) => {
// 创建画布的宽高属性节点,就是图片的大小,单位PX
let width = video.videoWidth;
let height = video.videoHeight;

//默认最大尺度的尺寸限制在(1920 * 1080)
const maxWidth = 1024,
maxHeight = 1024,
ratio = maxWidth / maxHeight;
//目标尺寸
let targetWidth = width,
targetHeight = height;
//当图片的宽度或者高度大于指定的最大宽度或者最大高度时,进行缩放图片
if (width > maxWidth || height > maxHeight) {
//超过最大宽高比例
if (width / height > ratio) {
//宽度取最大宽度值maxWidth,缩放高度
targetWidth = maxWidth;
targetHeight = Math.round(maxWidth * (height / width));
} else {
//高度取最大高度值maxHeight,缩放宽度
targetHeight = maxHeight;
targetWidth = Math.round(maxHeight * (width / height));
}
}

var anw = document.createAttribute("width");
anw.nodeValue = targetWidth;
var anh = document.createAttribute("height");
anh.nodeValue = targetHeight;
canvas.setAttributeNode(anw);
canvas.setAttributeNode(anh);
// 画布渲染
ctx.drawImage(video, 0, 0, targetWidth, targetHeight);
// 生成图片
var base64 = canvas.toDataURL("image/png", 0.8); // 这就是封面图片的base64编码
// 视频结束播放的事件
video.pause();

reslove(base64); // promise函数成功的回调
},
false
);
});
}

renderjs 是一个运行在视图层的 js。它比 WXS 更加强大。它只支持 app-vue 和 web。

主要作用

  1. 大幅降低逻辑层和视图层的通讯损耗,提供高性能视图交互能力

    uni-app 的 app 端逻辑层和视图层是分离的,这种机制有很多好处,但也有一个副作用是在造成了两层之间通信阻塞。尤其是 App 的 Android 端阻塞问题影响了高性能应用的制作。

    renderjs 运行在视图层,可以直接操作视图层的元素,避免通信折损。

  2. 在视图层操作 dom,运行 for web 的 js 库

    官方不建议在 uni-app 里操作 dom,但如果你不开发小程序,想使用一些操作了 dom、window 的库,其实可以使用 renderjs 来解决。

    在 app-vue 环境下,视图层由 webview 渲染,而 renderjs 运行在视图层,自然可以操作 dom 和 window。

注意事项

  1. 目前仅支持内联使用。
  2. 不要直接引用大型类库,推荐通过动态创建 script 方式引用。
  3. 可以使用 vue 组件的生命周期(不支持 beforeDestroydestroyedbeforeUnmountunmounted),不可以使用 App、Page 的生命周期
  4. 视图层和逻辑层通讯方式与 WXS 一致,另外可以通过 this.$ownerInstance 获取当前组件的 ComponentDescriptor 实例,使用 callMethod 方法,去抛出方法、传值,类似于 vue 组件间 emit
  5. 注意逻辑层给数据时最好一次性给到渲染层,而不是不停从逻辑层向渲染层发消息,那样还是会产生逻辑层和视图层的多次通信,还是会卡
  6. 观测更新的数据在视图层可以直接访问到。
  7. APP 端视图层的页面引用资源的路径相对于根目录计算,例如:./static/test.js。
  8. APP 端可以使用 dom、bom API,不可直接访问逻辑层数据,不可以使用 uni 相关接口(如:uni.request)
  9. H5 端逻辑层和视图层实际运行在同一个环境中,相当于使用 mixin 方式,可以直接访问逻辑层数据。
阅读全文 »

多表达式多 if 判断

我们可以在数组中存储多个值,并且可以使用数组 include 方法。

1
2
3
4
5
6
7
8
// 长
if (x === "abc" || x === "def" || x === "ghi" || x === "jkl") {
//logic
}
// 短
if (["abc", "def", "ghi", "jkl"].includes(x)) {
//logic
}

简写 if else

如果 if-else 的逻辑比较降低,可以使用下面这种方式镜像简写,当然也可以使用三元运算符来实现。

阅读全文 »

队列是数据结构中的一种,它与实际生活中的排队相似:在一条队伍中,先来的人总是能够先得到服务,后来的人只能排在队伍末尾等候。队列也是一样,它符合先进先出 FIFO(First Input First Out)的顺序。

队列的类型

队列有两种类型:一种是和日常排队类似的队列,叫做普通队列;另一种叫做环形队列

对于一个队列来说,有队头和队尾,以及容量。

普通队列

阅读全文 »

在 HTML 中会遇到以下三类 script:

1
2
3
<script src="xxx"></script>
<script src="xxx" async></script>
<script src="xxx" defer></script>

script 标签用于加载脚本与执行脚本,直接使用 script 脚本时,html 会按照顺序来加载并执行脚本,在脚本加载&执行的过程中,会阻塞后续的 DOM 渲染。

比如现在大家习惯于在页面中引用各种第三方脚本,但如果第三方服务商出现了一些小问题,比如延迟之类的,就会使得页面白屏。

针对上述情况,script 标签提供了两种方式来解决问题,就是加入属性 async 以及 defer,这两个属性使得 script 标签加载都不会阻塞 DOM 的渲染。

阅读全文 »

前言

每一个网页都离不开 css,但是很多人又认为,css 主要是用来完成页面布局的,像一些细节或者优化,就不需要怎么考虑,实际上这种想法是不正确的

作为页面渲染和内容展现的重要环节,css 影响着用户对整个网站的第一体验

因此,在整个产品研发过程中,css 性能优化同样需要贯穿全程

实现方式

阅读全文 »

思考:该处理是否必须同步完成?数据是否必须按顺序完成?

解决方案

  1. 将数据分页,利用分页的原理,每次服务器端只返回一定数目的数据,浏览器每次只对一部分进行加载。

  2. 使用懒加载的方法,每次加载一部分数据,其余数据当需要使用时再去加载。

  3. 使用数组分块技术,基本思路是为要处理的项目创建一个队列,然后设置定时器每过一段时间取出一部分数据,然后再使用定时器取出下一个要处理的项目进行处理,接着再设置另一个定时器。