应用场景
监控摄像头,多通道,如通道1,通道2,通道3,通道4,通道5,通道6。
一个属性值,用来表示拥有哪几个通道
每个通道作为一个复选框,使用
位运算
来高效地处理多选框的状态
应用逻辑
使用位运算来高效地处理多选框的状态。在计算机科学中,2 的幂次方在二进制表示中各自占据不同的位: 通道1的值:十进制是1,二进制是 000001 通道2的值:十进制是2,二进制是 000010 通道3的值:十进制是4,二进制是 000100 通道4的值:十进制是8,二进制是 001000 通道5的值:十进制是16,二进制是 010000 通道6的值:十进制是32,二进制是 100000
这种设计的优势:
- 可以通过简单的加法或按位或运算组合多个通道的值
- 可以通过按位与运算快速判断某个通道是否被选中
- 节省存储空间,一个整数就可以表示所有通道的选择状态
- 位运算天然避免重复值的影响
例如,如果选中了通道1、3和5,那么总值就是 1 + 4 + 16 = 21。要检查通道3是否被选中,只需要检查 21 & 4 是否等于 4。
前置知识
reduce函数
是 JavaScript 数组的一个高阶函数方法,用于对数组中的每个元素执行一个回调函数,并将数组缩减为一个单一的值。
基本语法:
js
array.reduce(callback(accumulator, currentValue, currentIndex, array), initialValue)
//或
array.reduce((accumulator, currentValue, currentIndex, array) => {}, initialValue)
参数说明:
callback
: 执行数组中每个元素的函数,包含以下参数:accumulator
:上一次调用回调函数返回的值,或者是提供的初始值currentValue
:当前正在处理的数组元素currentIndex
(可选):当前处理元素的索引array
(可选):调用 reduce 的数组
initialValue
(可选):作为第一次调用 callback 函数时的第一个参数的值
示例演示:
js
// 数组内每个元素相加得到的结果(可以遍历相加,此处是使用reduce函数和位或运算得到结果)
const videoChannelList = [1,4,16]
const value = videoChannelList.reduce((accumulator, currentValue) => accumulator | currentValue, 0);
这里的工作原理是:
- 初始值为 0
- 对于数组中的每个值,执行按位或运算(|)
- 逐步累积结果,最终得到一个合并值
例如:如果选中了通道1(1)、通道3(4)和通道5(16):
- 第一次:0 | 1 = 1
- 第二次:1 | 4 = 5
- 第三次:5 | 16 = 21
- 最终结果:21
这种方式利用了位运算的特性,每个通道值都是2的幂次方,在二进制中只有一个位为1,通过按位或运算可以安全地合并这些值。
Math.pow()函数
是 JavaScript 中用于计算幂运算的内置函数。
基本语法:
js
Math.pow(base, exponent)
参数说明:
- base:底数
- exponent:指数
返回值:
返回 base 的 exponent 次幂,即 base^exponent。
例如:
js
Math.pow(2, 3) // 返回 8 (2的3次方)
Math.pow(4, 0.5) // 返回 2 (4的平方根)
Math.pow(10, -1) // 返回 0.1 (10的负一次方)
const bitValue = 1 << i;
: 使用位移运算符计算2的i次方
功能:
- 1 << i 表示将数字1的二进制向左移动i位
- 等价于计算 Math.pow(2, i) 或 2^i
- 用于生成二进制中只有第i位为1的数值
示例演示:
html
<el-checkbox v-for="item in 6" :label="Math.pow(2, item - 1)" :key="item">
通道{{item}}
</el-checkbox>
具体生成的值为:
- 当 item=1 时,Math.pow(2, 0) = 1
- 当 item=2 时,Math.pow(2, 1) = 2
- 当 item=3 时,Math.pow(2, 2) = 4
- 当 item=4 时,Math.pow(2, 3) = 8
- 当 item=5 时,Math.pow(2, 4) = 16
- 当 item=6 时,Math.pow(2, 5) = 32
可以通过按位或运算 (|) 安全地合并 可以通过按位与运算 (&) 检查某个位是否被设置 这种方式常用于权限系统或状态标记,因为它能高效地组合和检查多个标志位。
应用实操
xxx.vue
html
<template>
...
<el-form-item label="视频通道" prop="videoChannel">
<el-checkbox-group v-model="videoChannelList">
<!--
这里会生成 6 个复选框,每个复选框的 label 值分别是:
当 item=1 时,label=Math.pow(2, 0) = 1
当 item=2 时,label=Math.pow(2, 1) = 2
当 item=3 时,label=Math.pow(2, 2) = 4
当 item=4 时,label=Math.pow(2, 3) = 8
当 item=5 时,label=Math.pow(2, 4) = 16
当 item=6 时,label=Math.pow(2, 5) = 32
-->
<el-checkbox v-for="item in 6" :label="Math.pow(2, item - 1)" :key="item" @change="handleCheckChange('video')">
通道{{item}}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-button @click="selectValueFun">取值({{result}})</el-button>
<el-button @click="echoFun">回显</el-button>
</template>
<script setup>
import { ref } from "vue";
// 被勾选的一个或多个复选框返回数组,如勾选通道1、通道3和通道5,返回的数组是[1,4,16]
const videoChannelList = ref([])
const channelValue = 21
const result = ref(0)
// 回显哪些复选框被选中
const echoFun = () => {
//视频通道打钩
for (let i = 0; i < 6; i++) {
/*
表示将数字1的二进制向左移动i位
-等价于计算 Math.pow(2, i) 或 2^i(2的i次幂)
-用于生成二进制中只有第i位为1的数值
*/
const bitValue = 1 << i;
if ((channelValue & bitValue) !== 0) {
videoChannelList.value.push(bitValue);
}
}
}
// 选中一个或多个复选框后的值
const selectValueFun = () => {
// channel初始值为 0,并与当前值val(遍历数组中的每个值),执行按位或运算(|),获取最终的值(相当于每个元素值相加后的结果,但仅限于元素值为2^i时)
const value = videoChannelList.value.reduce((channel, val) => channel | val, 0);
result.value = value;
}
</script>