uni.$emit

  • 如果没有提供参数,则移除所有的事件监听器
  • 如果只提供了事件,则移除该事件所有的监听器
  • 如果同时提供了事件与回调,则只移除这个回调的监听器
  • 提供的回调必须跟$on 的回调为同一个才能移除这个回调的监听器

发送

1
uni.$emit("update", { msg: "页面更新" });

监听

阅读全文 »

getBoundingClientRect

getBoundingClientRect() 是一个用于获取元素位置和尺寸信息的方法。它返回一个 DOMRect 对象,其提供了元素的大小及其相对于视口的位置,其中包含了以下属性:

  • x:元素左边界相对于视口的 x 坐标。
  • y:元素上边界相对于视口的 y 坐标。
  • width:元素的宽度。
  • height:元素的高度。
  • top:元素上边界相对于视口顶部的距离。
  • right:元素右边界相对于视口左侧的距离。
  • bottom:元素下边界相对于视口顶部的距离。
  • left:元素左边界相对于视口左侧的距离。
1
2
3
4
5
6
7
8
9
10
11
const box = document.getElementById("box");
const rect = box.getBoundingClientRect();

console.log(rect.x); // 元素左边界相对于视口的 x 坐标
console.log(rect.y); // 元素上边界相对于视口的 y 坐标
console.log(rect.width); // 元素的宽度
console.log(rect.height); // 元素的高度
console.log(rect.top); // 元素上边界相对于视口顶部的距离
console.log(rect.right); // 元素右边界相对于视口左侧的距离
console.log(rect.bottom); // 元素下边界相对于视口顶部的距离
console.log(rect.left); // 元素左边界相对于视口左侧的距离

应用场景

阅读全文 »

普通函数

1
2
3
4
5
const add10 = (x) => x + 10;
const mul10 = (x) => x * 10;
const add100 = (x) => x + 100;

console.log(add10(mul10(add100(10)))); // (10 + 100) * 10 + 10 = 1110

我们想输出的是一个多层函数嵌套的运行结果,即把前一个函数的运行结果赋值给后一个函数。但是如果需要嵌套多层函数,那这种类似于 f(g(h(x)))的写法可读性太差,我们考虑能不能写成(f, g, h)(x)这种简单直观的形式,于是 compose()函数就正好帮助我们实现。

compose

compose 函数是一种函数式编程的概念,它可以将多个函数组合成一个新的函数。在 JavaScript 中,compose 函数的实现通常是使用 reduceRight 方法,从右到左依次执行每个函数。

阅读全文 »

一道面试题引发的思考

从上到下依次说出执行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var foo = function () {
console.log("foo1");
};
foo();

var foo = function () {
console.log("foo2");
};
foo();

function foo() {
console.log("foo1");
}
foo();

function foo() {
console.log("foo2");
}
foo();

输出结果:foo1 foo2 foo2 foo2

分析

阅读全文 »

概念

按位取反是指将一个二进制数的每一位都取反,即 0 变为 1,1 变为 0。在很多编程语言中,可以通过使用位运算符~来实现按位取反操作。

运算规则

  1. 将要取反的二进制数转换为二进制补码表示法。
  2. 对二进制补码表示法的每一位进行取反操作。
  3. 将取反后的二进制数转换回十进制表示法。

示例

阅读全文 »

文件传输是一个常见的需求。对于大文件的下载和上传,直接使用传统的方式可能会遇到性能和用户体验方面的问题。

幸运的是,前端技术提供了一些高效的解决方案:文件流操作和切片下载与上传。本文将深入探讨这些技术,帮助你理解它们的原理和实现方法,以优化文件传输效率和提升用户体验。

前端文件流操作

在前端开发中,文件流操作是指通过数据流的方式处理文件,对文件进行读取、写入和展示等操作。下面详细介绍了前端文件流操作的几个基本概念和技术。

数据流和文件处理的基本概念

数据流是指连续的数据序列,可以从一个源传输到另一个目的地。在前端开发中,文件可以被看作数据流的一种形式,可以通过数据流的方式进行处理。 文件处理涉及读取和写入文件的操作,包括读取文件的内容、写入数据到文件,以及对文件进行删除、重命名等操作。

阅读全文 »

app 端

ux-webview.vue
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
<template>
<web-view
:ref="webviewRefName"
:src="webViewUrl"
:allow="allow"
:sandbox="sandbox"
@message="message"
@onPostMessage="onPostMessage" />
</template>

<script>
import WebView from "./WebView.js";

export default {
props: {
src: {
type: String
},
allow: {
type: String
},
sandbox: {
type: String
},
UniJsBridgeName: {
type: String,
default: "wv"
}
},
data() {
return {
webView: null,
webViewUrl: "",
webviewRefName: null
};
},
created() {
this.webViewUrl = this.src || this.$Route.query.url || "";
this.webviewRefName =
"webview_" + new Date().getTime() + "_" + Math.ceil(Math.random() * 10);
},
mounted() {
let webviewRef = this.$refs[this.webviewRefName];
this.webView = new WebView(webviewRef, this.UniJsBridgeName);
},
methods: {
message() {
this.$emit("message", { ...arguments });
},
onPostMessage(data) {
let message = data.detail;
if (message) {
let { data, callbackId, handlerName } = message.data[0];
/**
* handlerName为response的时候,这个时候的callbackId为客户端的回调函数ID
* 其他的时候,callbackId为H5的回调函数ID
*/
if (handlerName === "response") {
/**
* 找到对应的回调函数
* 执行完毕后立马删除,否则集合中的东西太多了
*/
let responseCallback = this.webView.responseCallbacks[callbackId];
if (responseCallback) {
responseCallback(data);
delete this.webView.responseCallbacks[callbackId];
}
} else {
let messageHandler = this.webView.messageHandlers[handlerName];
let call = (data) => {
this.webView.call(null, data, null, callbackId);
};

if (messageHandler) {
messageHandler(data, call);
}
}
}
this.$emit("onPostMessage", data);
},
call() {
this.webView.call.apply(this.webView, arguments);
},
regist() {
this.webView.regist.apply(this.webView, arguments);
},
init() {
this.webView.init.apply(this.webView, arguments);
},
send() {
this.webView.send.apply(this.webView, arguments);
}
}
};
</script>
webView.js
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
70
71
72
class WebView {
messageHandlers = {};
responseCallbacks = {};
uniqueId = 1;
/**
* webView: uni-app 的webview组件
* UniJsBridgeName: 前端挂载在window下的全局方法,全局变量为wv
*/
constructor(webView, UniJsBridgeName = "wv") {
this.webViewRef = webView;
this.UniJsBridgeName = UniJsBridgeName;
}

/**
* 调用前端JS,都需要通过此函数
*
* @param {String} handlerName 前端注册的函数名
* @param {Object} data 给前端的回调的参数
* @param {Function} callback 调用完前端的回调
*/
call(handlerName, data, responseCallback, responseId) {
let messageJSON = {
handlerName, // 前端注册的函数名
responseId, // 前端对应的自己的回调函数
responseData: data // 给前端的参数
};

/**
* 把回调函数存在集合中
* 等待H5来调用
* @param {Object} responseCallback
*/
if (responseCallback) {
let callbackId =
"uni_app_cb_" + this.uniqueId++ + "_" + new Date().getTime();
this.responseCallbacks[callbackId] = responseCallback;
messageJSON.callbackId = callbackId;
}

messageJSON = JSON.stringify(messageJSON);
this.webViewRef.evalJs(
`${this.UniJsBridgeName}._handleMessageFromNative(${messageJSON})`
);
}

/**
* 注册线程 往数组里面添加值,被动的等待着H5调用的
* @param {Object} handlerName
* @param {Object} handler
*/
regist(handlerName, handler) {
this.messageHandlers[handlerName] = handler;
}

/**
* 设置默认处理函数,如果前端用send函数给客户端发消息,就走此函数
* 其实和regist是一样的,只不过可以省略一个参数
*/
init(handler) {
this.messageHandlers["send"] = handler;
}

/**
* 向H5发消息
* @param {Object} message
*/
send(message, responseCallback) {
this.call(null, message, responseCallback);
}
}

export default WebView;

示例:

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
<template>
<view class="page">
<view class="fromH5Message">
<view class="message">来着H5的消息: {{ fromH5Message }}</view>
</view>
<button type="default" @tap="callH5">调用H5提前注册好的函数</button>
<button type="default" @tap="initH5">调用H5提前注册好的默认处理函数</button>
<ux-webview ref="wv" class="webview" src="http://0.0.0.0:8000" />
</view>
</template>

<script>
export default {
data() {
return {
count: 0,
fromH5Message: ""
};
},
onLoad() {
setTimeout(() => {
/**
* 先注册一个函数给H5调用
*/
this.$refs.wv.regist("nativeShow", (data, cb) => {
this.fromH5Message = JSON.stringify(data);

cb({
data: "nativeShow的消息" + new Date().getTime()
});
});

/**
* 设置一个默认处理函数
*/
this.$refs.wv.init((data, cb) => {
cb({ send: "给H5的" });
});
});
},
methods: {
callH5() {
this.$refs.wv.call(
"test",
{ toH5Data: "给H5的参数" + Date.now() },
(data) => {
this.fromH5Message = JSON.stringify(data);
}
);
},
initH5() {
this.$refs.wv.send({ fff: "1000.013213" }, function (data) {
this.fromH5Message = "send" + JSON.stringify(data);
});
}
}
};
</script>
阅读全文 »

img

1
<img src="图片来源" alt="图片无法显示时显示图片说明性文字" style="设置样式属性" />
  • img 标签虽然不是块状元素,但是可以设置宽高,占位

  • img 设置 width 后 height 会自适应匹配,如果设置 height 后 width 会自适应匹配,如果同时设置 width,height,img 图片可能会变形

background-image

  • css 的一个样式,并不占位,可以结合 background-size,background-repeat,background-position 等属性来设置图片位置,大小等

  • 所在的元素必须指定 height,否则背景图片显示不出来,可以不指定 width,如果不指定 width,它的宽度则继承父元素的宽度

阅读全文 »