使用VUE自定义组件封装部门选择功能

article/2025/7/12 15:42:56

背景

照惯例,先交待下背景,从真实需求出发,讲述实现效果、设计思路和实现方式。
软件系统中,会有一些常见常用的选择功能,如部门选择、人员选择等,用于填报表单,使用频率很高。直接使用一方面会比较繁琐,另一方面造成代码重复,当需要调整时,则需要遍历整个项目源码,容易因漏改引发问题。这种情况下,更好的实现方案,是通过封装组件,来实现简化使用和复用的目的。
前面有一篇,介绍了使用VUE自定义组件封装数据字典,功能比较简单,今天进一步,封装一个比较复杂的部门单选组件,其他业务实体,如人员、角色等,实现非常类似,就不再赘述。

实现效果

首先展示下实现效果。
用户管理列表,左边是部门树,右侧是用户列表,如下图。
在这里插入图片描述
点击“新增”按钮,打开用户编辑页面,自动显示传入的部门。
在这里插入图片描述

第一行就是我们封装的部门单选组件,点击最右侧的图标,弹出部门选择页面来。
在这里插入图片描述

选择新部门后,确定,即可实现部门的变更。

站在使用的角度看,也非常简单,用户编辑页面整体源码如下

<template><el-dialog :title="title" :visible="visible" @close="visible=false"><el-formref="form":model="entityData":rules="rules"label-width="80px"label-position="right"style="width:90%;margin:0px auto;"><!--表单区域 --><el-form-item label="组织机构" prop="organizationId"><organization-single-selectv-model="entityData.organizationId"/></el-form-item><el-form-item label="账号" prop="account"><el-input v-model="entityData.account" /></el-form-item><el-form-item label="姓名" prop="name"><el-input v-model="entityData.name" /></el-form-item><el-form-item label="职务" prop="position"><el-input v-model="entityData.position" /></el-form-item><el-form-item label="性别" prop="gender"><dictionary-radio-groupv-model="entityData.gender":code="constant.DICTIONARY_TYPE_CODES.GENDER"/></el-form-item><el-form-item label="出生日期" prop="birthday"><el-date-pickerv-model="entityData.birthday"value-format="yyyy-MM-dd HH:mm:ss"format="yyyy年MM月dd日"type="date"placement="bottom-end"placeholder="请选择"class="form-item"/></el-form-item><el-form-item label="手机号" prop="telephone"><el-input v-model="entityData.telephone" /></el-form-item><el-form-item label="邮箱地址" prop="email"><el-input v-model="entityData.email" /></el-form-item><el-form-item label="状态" prop="status"><dictionary-radio-groupv-model="entityData.status":code="constant.DICTIONARY_TYPE_CODES.STATUS"/></el-form-item><el-form-item label="排序号" prop="orderNo"><el-input v-model="entityData.orderNo" /></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button v-show="saveButtonVisible" type="primary" @click="save">保存</el-button><el-button @click="close">关闭</el-button></div></el-dialog>
</template>

,引入部门单选组件后,具体使用的时候,只需要如下代码即可

<el-form-item label="组织机构" prop="organizationId"><organization-single-selectv-model="entityData.organizationId"/></el-form-item>

也就是说,封装组件后,使用部门单选功能,跟使用一个文本输入框类似,所有与之相关的页面展现和逻辑处理都在组件内部实现了,是不是对使用方非常友好?

设计与实现

技术栈采用的还是vue2.0,UI组件库使用element ui。

使用简单,是因为将复杂工作封装在了内部,这里同样用组件化的思路,将部门单选组件拆分成了两个vue页面,一个是整体组件,负责文本框的展示,对弹出部门选择页面的调度,另一个是负责具体的部门选择。

源码实现

先附上整体组件源码

<template><div><el-input v-model="organizationName" disabled><el-button slot="append" icon="el-icon-s-grid" @click="openModal" /></el-input><organization-modal ref="organizationModel" @ok="handleOK" /></div>
</template><script>
import OrganizationModal from './OrganizationModal'
export default {name: 'OrganizationSingleSelect',components: {OrganizationModal},model: {prop: 'value',event: 'change'},props: {width: {type: Number,default: 500,required: false},value: {type: String,default: '',required: false},disabled: {type: Boolean,required: false,default: false}},data() {return {visible: false,organizationName: ''}},watch: {value: {immediate: true,handler: 'handleValue'}},methods: {openModal() {this.$refs.organizationModel.show(this.value, this.organizationName)},handleValue() {if (this.value) {this.$api.system.organization.get(this.value).then((res) => {this.organizationName = res.data.name})}},handleOK(id) {// 更新父组件绑定值this.$emit('change', id)}}
}
</script><style scoped>
</style>

注意事项

下面重点说下封装需要注意的点。

1.UI元素比较简单,就一个文本框,默认设置为禁用状态,并且追加了一个按钮,用于触发部门选择页面的弹出。

 <el-input v-model="organizationName" disabled><el-button slot="append" icon="el-icon-s-grid" @click="openModal" /></el-input>

在这基础上当然也可以进行功能扩展,如再追加一个清空已选择的按钮,视需求而定。
2.很重要的一点,是设置model选项。因为默认情况下,model使用名为 value 的 prop 和名为 input 的事件,而我们封装的效果是选择控件,将文本框禁用了,事件应该使用chang而不是input,所以需要做如下设置:

 model: {prop: 'value',event: 'change'}

3.为了组件的可配置性,设置了部分prop属性,如宽度、是否禁用等,这样在使用的时候,就能通过属性绑定的方式灵活配置了。

 width: {type: Number,default: 500,required: false},value: {type: String,default: '',required: false},disabled: {type: Boolean,required: false,default: false}

4.通过vue的watch机制,监视value的变化,该值变化后,调用后端部门服务接口,拿到部门名称后更新显示。

  watch: {value: {immediate: true,handler: 'handleValue'}},……handleValue() {if (this.value) {this.$api.system.organization.get(this.value).then((res) => {this.organizationName = res.data.name})}}

5.选择项变化时,通过change事件,调用emit,把最新的值传递给使用方,这一步很关键。

 change(value) {this.$emit('change', value)}

接下来看下部门选择页面的实现,完整源码如下:

<template><div><el-dialog title="组织机构——单选" :visible="visible" width="400px" append-to-body @close="close"><el-input v-model="searchValue" placeholder="请输入关键字过滤" style="margin-bottom:10px" /><el-tag>当前机构:{{ selectedName }}</el-tag><el-treeref="tree":data="treeData"node-key="id":default-expanded-keys="defaultExpandedKeys":filter-node-method="filterNode"@current-change="handleTreeSelectChange"/><div slot="footer" class="dialog-footer"><el-button type="primary" @click="confirm">确定</el-button><el-button @click="close">关闭</el-button></div></el-dialog></div>
</template><script>export default {data() {return {visible: false,treeData: [],searchValue: '',defaultExpandedKeys: [],selectedValue: '',selectedName: ''}},watch: {searchValue(value) {this.$refs.tree.filter(value)}},methods: {show(id, name) {this.searchValue = ''this.defaultExpandedKeys = []this.selectedValue = idthis.selectedName = namethis.loadTree()this.visible = true},loadTree() {this.$api.system.organization.tree().then(res => {this.treeData = res.data// 默认展开根节点this.defaultExpandedKeys.push(this.treeData[0].id)// 默认展开当前节点this.defaultExpandedKeys.push(this.selectedValue)})},close() {this.visible = false},confirm() {this.$emit('ok', this.selectedValue)this.visible = false},// 树节点选中改变handleTreeSelectChange(data) {this.selectedValue = data.idthis.selectedName = data.label},filterNode(value, data) {if (!value) return truereturn data.label.indexOf(value) !== -1}}
}</script><style scoped>
</style>

具体功能包括了数据加载、默认展开、显示已选择值、搜索功能,已经可以满足常见的需求了。

多选功能的实现

上面实现了单选功能,其实多选功能实现也类似,这里只放代码,就不再展开介绍了

<template><div><el-input v-model="organizationName" disabled><el-button slot="append" icon="el-icon-s-grid" @click="openModal" /></el-input><organization-modal ref="organizationModel" @ok="handleOK" /></div>
</template><script>
import OrganizationModal from './organizationModal'
export default {name: 'OrganizationMultipleSelect',components: {OrganizationModal},model: {prop: 'value',event: 'change'},props: {value: {type: String,default: '',required: false},width: {type: Number,default: 500,required: false},disabled: {type: Boolean,required: false,default: false}},data() {return {visible: false,organizationName: ''}},watch: {value: {immediate: true,handler: 'handleValue'}},methods: {openModal() {this.$refs.organizationModel.show(this.value)},handleValue() {if (this.value) {const idList = this.value.split(',')this.$api.system.organization.getOrganization({ idList: idList }).then((res) => {this.organizationName = res.data.map(x => x.name).join(',')})}},handleOK(value) {// 处理父组件绑定值this.$emit('change', value.join(','))}}
}
</script><style scoped>
</style>
<template><div><el-dialog title="组织机构——多选" :visible="visible" width="400px" append-to-body @close="close"><el-input v-model="searchValue" placeholder="请输入关键字过滤" style="margin-bottom:10px" /><el-treeref="tree":data="treeData"node-key="id"show-checkbox:default-expanded-keys="defaultExpandedKeys":filter-node-method="filterNode":default-checked-keys="checkedNodesId"/><div slot="footer" class="dialog-footer"><el-button type="primary" @click="confirm">确定</el-button><el-button @click="close">关闭</el-button></div></el-dialog></div>
</template><script>export default {data() {return {visible: false,treeData: [],searchValue: '',defaultExpandedKeys: [],selectedValue: [],checkedNodesId: []}},watch: {searchValue(value) {this.$refs.tree.filter(value)}},methods: {show(idList) {this.searchValue = ''this.defaultExpandedKeys = []this.selectedValue = idListthis.loadTree()this.visible = true},loadTree() {this.$api.system.organization.tree().then(res => {this.treeData = res.data// 默认展开根节点this.defaultExpandedKeys.push(this.treeData[0].id)this.checkedNodesId = []this.getLeafNodeChecked(this.treeData)this.$refs.tree.setCheckedKeys(this.checkedNodesId)})},close() {this.visible = false},confirm() {this.$emit('ok', this.$refs.tree.getCheckedKeys())this.visible = false},filterNode(value, data) {if (!value) return truereturn data.label.indexOf(value) !== -1},getLeafNodeChecked(node) {// 遍历树节点,设置for (const treeNode of node) {// 如果节点有子节点,那他的选中状态不被考虑,继续往下找if (treeNode.children && treeNode.children.length > 0) {this.getLeafNodeChecked(treeNode.children)} else {// 是叶子节点,如果是check状态就记录if (this.selectedValue.includes(treeNode.id)) {this.checkedNodesId.push(treeNode.id)}}}}}
}</script><style scoped>
</style>

Vue3的实现方案

对于组件的封装,设计和实现思路不变的,并不受vue2还是vue3的影响。不过,vue3版本还是做了一些调整,以及Element plus也做了相应调整,补充一下vue3+Element Plus环境下的组件封装。

单选功能

<template><div class="w-full"><el-input v-model="displayName" disabled style="width: 152px" /><el-button-group><el-button icon="grid" @click="init" style="border-left-width: 0; padding: 10px" /><el-button icon="delete" @click="clear" style="border-left-width: 0; padding: 10px" /></el-button-group><Dialog title="组织机构选择" v-model="visible" width="300px"><el-input v-model="searchValue" placeholder="请输入名称查询" style="margin-bottom: 10px" /><el-tag>当前选中:{{ currentName }}</el-tag><el-treeref="tree"class="aside-tree":data="treeData"node-key="id":filter-node-method="filterNode":default-expanded-keys="cacheTreeExpandedKeys"@current-change="handleTreeSelectChange"@node-expand="handleNodeExpand"@node-collapse="handleNodeCollapse"/><template #footer><el-button type="primary" @click="confirm">确定</el-button><el-button @click="close">关闭</el-button></template></Dialog></div>
</template><script>
import { treeReferenceMixin } from '@/mixin/treeReferenceMixin.js'
const MODULE_CODE = 'system'
const ENTITY_TYPE = 'organization'
export default {mixins: [treeReferenceMixin],data() {return {entityType: ENTITY_TYPE,moduleCode: MODULE_CODE,// eslint-disable-next-line no-evalapi: eval('this.$api.' + MODULE_CODE + '.' + ENTITY_TYPE),pageCode: MODULE_CODE + ':' + ENTITY_TYPE + ':',// 名称键值nameKey: 'name'}},methods: {}
}
</script><style></style>

这里使用了mixin混入功能,代码如下:

/*** 树参照页面混入*/
import { Dialog } from '@/components/abc/Dialog'export const treeReferenceMixin = {emits: ['update:modelValue', 'my-change', 'change-selected', 'change'],components: {Dialog},data() {return {treeData: [],cacheTreeExpandedKeys: [],currentId: '',currentName: '',// 显示名称displayName: '',// 搜索值searchValue: '',// 可见性visible: false}},props: {modelValue: {type: String,default: '',required: false},disabled: {type: Boolean,required: false,default: false}},watch: {modelValue: {immediate: true,handler: 'getSelectedName'},searchValue(value) {this.$refs.tree.filter(value)}},methods: {// 初始化init(param) {if (this.beforeInit != null) {this.beforeInit(param)}this.currentId = this.modelValuethis.loadData().then((res) => {if (this.afterInit) {this.afterInit(param)}this.visible = true})},loadData() {return new Promise((resolve) => {this.api.tree().then((res) => {this.treeData = res.data// 如没有默认选中节点if (!this.currentId || this.currentId === '') {// 默认设置根节点this.currentId = this.treeData[0].idthis.currentName = this.treeData[0].label// 设置根节点默认展开this.cacheTreeExpandedKeys.push(this.treeData[0].id)// 手工触发选择节点改变this.$emit('change-selected', this.treeData[0].id, this.treeData[0].label)} else {// 默认展开当前节点this.cacheTreeExpandedKeys.push(this.currentId)// 手工触发选择节点改变this.$emit('change-selected', this.currentId, this.currentName)}resolve()})})},// 树表相关操作handleTreeSelectChange(data) {// 保存标识及名称用于新增操作this.currentId = data.idthis.currentName = data.labelthis.$emit('change-selected', this.currentId, this.currentName)},// 展开树节点handleNodeExpand(data) {this.cacheTreeExpandedKeys.push(data.id)},// 折叠树节点handleNodeCollapse(data) {const index = this.cacheTreeExpandedKeys.findIndex((item) => item === data.id)this.cacheTreeExpandedKeys.splice(index, 1)},// 根据名称查询树节点filterNode(value, data) {if (!value) return truereturn data.label.indexOf(value) !== -1},close() {this.visible = false},confirm() {// 更新父组件绑定值this.$emit('update:modelValue', this.currentId)this.$emit('my-change', this.currentId)this.visible = false},// 清空选择clear() {this.displayName = ''this.$emit('update:modelValue', '')this.$emit('my-change', '')},// 获取选中的名称getSelectedName() {if (this.modelValue) {this.api.get(this.modelValue).then((res) => {this.displayName = res.data[this.nameKey]this.currentName = this.displayName})}}},provide() {return {}}
}

多选功能

<template><div class="w-full"><el-input v-model="displayName" disabled style="width: 152px" /><el-button-group><el-button icon="grid" @click="init" style="border-left-width: 0; padding: 10px" /><el-button icon="delete" @click="clear" style="border-left-width: 0; padding: 10px" /></el-button-group><Dialog title="组织机构——多选" v-model="visible" width="300px"><el-input v-model="searchValue" placeholder="请输入过滤值" style="margin-bottom: 10px" /><el-treeref="tree"class="aside-tree":data="treeData"node-key="id"show-checkbox:filter-node-method="filterNode":default-expanded-keys="cacheTreeExpandedKeys":default-checked-keys="checkedNodesId"/><template #footer><el-button type="primary" @click="confirm">确定</el-button><el-button @click="close">关闭</el-button></template></Dialog></div>
</template><script>
import { treeMultipleReferenceMixin } from '@/mixin/treeMultipleReferenceMixin.js'
const MODULE_CODE = 'system'
const ENTITY_TYPE = 'organization'
export default {mixins: [treeMultipleReferenceMixin],data() {return {entityType: ENTITY_TYPE,moduleCode: MODULE_CODE,// eslint-disable-next-line no-evalapi: eval('this.$api.' + MODULE_CODE + '.' + ENTITY_TYPE),pageCode: MODULE_CODE + ':' + ENTITY_TYPE + ':'}},methods: {}
}
</script><style></style>

mixin混入代码如下:

/*** 树多选页面混入*/
import { Dialog } from '@/components/abc/Dialog'export const treeMultipleReferenceMixin = {emits: ['confirm'],components: {Dialog},props: {modelValue: {type: Array,default: () => [],required: false}},data() {return {treeData: [],cacheTreeExpandedKeys: [],// 显示名称displayName: '',// 搜索值searchValue: '',// 可见性visible: false,checkedNodesId: [],selectedValue: []}},watch: {modelValue: {immediate: true,handler: 'getSelectedName'},searchValue(value) {this.$refs.tree.filter(value)}},methods: {// 初始化init(param) {if (this.beforeInit != null) {this.beforeInit(param)}this.searchValue = ''this.cacheTreeExpandedKeys = []this.selectedValue = this.modelValuethis.loadData().then((res) => {if (this.afterInit) {this.afterInit(param)}this.visible = true})},loadData() {return new Promise((resolve) => {this.api.tree().then((res) => {this.treeData = res.data// 默认展开根节点this.cacheTreeExpandedKeys.push(this.treeData[0].id)this.checkedNodesId = []this.getLeafNodeChecked(this.treeData)resolve()})})},// 根据名称查询树节点filterNode(value, data) {if (!value) return truereturn data.label.indexOf(value) !== -1},close() {this.visible = false},// 清空选择clear() {this.displayName = ''this.$emit('update:modelValue', [])},confirm() {// 获取半选节点IDconst halfCheckedKeys = this.$refs.tree.getHalfCheckedKeys()// 拼接全选节点IDconst idList = halfCheckedKeys.concat(this.$refs.tree.getCheckedKeys())this.$emit('update:modelValue', idList)this.visible = false},getLeafNodeChecked(node) {if (this.selectedValue) {// 遍历树节点,设置for (const treeNode of node) {// 如果节点有子节点,那他的选中状态不被考虑,继续往下找if (treeNode.children && treeNode.children.length > 0) {this.getLeafNodeChecked(treeNode.children)} else {// 是叶子节点,如果是check状态就记录if (this.selectedValue.includes(treeNode.id)) {this.checkedNodesId.push(treeNode.id)}}}}},// 获取选中的名称getSelectedName() {let length = 0if (this.modelValue) {length = this.modelValue.length}this.displayName = '已选择[ ' + length + ' ]条'}}
}

最后需要说一下的是,通过组件化的思想,可以将大型的复杂功能拆分成一个个小的功能组件,这些小组件可以独立进行开发、测试和维护,从而降低了整个系统的复杂性,同时也提高了整个系统的可维护性和可扩展性。这种组件化的方法可以大大提高开发效率和降低开发成本,同时也提高了系统的稳定性和性能。另外,这种组件化的思想还可以促进代码的复用,因为一个小的功能组件可以在不同的系统中进行重用,从而减少了代码的重复编写,提高了开发效率和代码质量。总的来说,组件化的思想是一种非常有用和实用的开发方法,可以使得开发更加高效、灵活和可靠。


http://chatgpt.dhexx.cn/article/ceP0sRvv.shtml

相关文章

选择部门(多层级)下人员

一、顶部部门选中标题栏&#xff08;部门面包屑&#xff09; 1.使用水平滚动的ListView&#xff08;HorizontalListView&#xff09;&#xff0c;代码搜索一下就能找到&#xff0c; 2.右监听可以使用符号文字>&#xff08;代码&#xff1a;>&#xff09;&#xff0c;也…

阿里云成立13年首次实现年度盈利;iPhone14有望实现息屏显示;Android 13将采用华为研发的只读文件系统 |EA周报...

EA周报 2022年5月27日 每个星期7分钟&#xff0c;元宝带你喝一杯IT人的浓缩咖啡&#xff0c;了解天下事、掌握IT核心技术。 周报看点 1、成立13年首次年度盈利&#xff0c;阿里云2022财年赚11亿 2、博通官宣610亿美元收购VMware 3、Android 13 将默认采用华为开发的只读文件系统…

【ELT.ZIP】OpenHarmony啃论文俱乐部—数据密集型应用内存压缩

本文出自ELT.ZIP团队&#xff0c;ELT<>Elite(精英)&#xff0c;.ZIP为压缩格式&#xff0c;ELT.ZIP即压缩精英。成员&#xff1a; 上海工程技术大学大二在校生合肥师范学院大二在校生清华大学大二在校生成都信息工程大学大一在校生黑龙江大学大一在校生华南理工大学大一在…

Nydus 镜像扫描加速

文&#xff5c;余硕 上海交通大学22届毕业生 阿里云开发工程师 从事云原生底层系统的开发和探索工作。 本文 6369 字 阅读 16 分钟 GitLink 编程夏令营是在 CCF 中国计算机学会指导下&#xff0c;由 CCF 开源发展委员会&#xff08;CCF ODC&#xff09;举办的面向全国高校学生的…

定了,6大领域93个开源任务,阿里开源导师带你参与中科院开源之夏2022

今年&#xff0c;由阿里巴巴开源导师参与的30个核心开源社区再次加入中国科学院软件研究所开源软件供应链点亮计划支持下的系列高校开源活动——开源之夏2022&#xff0c;共开放93个开源任务。通过本活动&#xff0c;同学们可以在顶级开源导师的指导下&#xff0c;通过3个月的时…

龙蜥操作系统 Anolis OS 8.6 - 来自阿里云的 CentOS 8 100% 兼容发行版

请访问原文链接&#xff1a;https://sysin.org/blog/anolis-os-8/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;www.sysin.org Anolis OS 8 是 OpenAnolis 社区推出的完全开源、中立、开放的发行版&#xff0c;它支持多计算架构&#x…

remove是什么意思计算机语言,remove是什么意思?remove是什么意思?

remove()是C语言中的函数&#xff0c;一般作用是删除数组、链表对象所有的元素。函数原型是intremove(char*filename)。 函数功能 remove()函数用于删除指定的文件&#xff0c;其原型如下&#xff1a; int remove(char *filename); 函数声明2&#xff1a; templateinline bool …

Linux 知:文件系统

文章目录 1. 前言2. 文件2.1. 一切皆文件2.2. 文件属性2.3. 目录结构2.4. 文件路径 3. 文件系统3.1. 文件系统种类3.2. 文件系统特性3.2.1. 格式化3.2.2. 格式 3.3. EXT 族文件系统3.3.1. EXT2 文件系统3.3.1.1. data block&#xff08;数据区块&#xff09;3.3.1.2. inode tab…

8 亿邮件地址泄露,源于邮件验证服务;腾讯推出微信公众号直播工具

(给技术最前线加星标&#xff0c;每天看技术热点) 转自&#xff1a;开源中国、solidot、cnBeta、腾讯科技、快科技等 【技术资讯】 0、8 亿邮件地址遭泄露&#xff0c;源于邮件验证服务 近日&#xff0c;Security Discovery 安全研究人员 Bob Diachenko 发现了一个150 GB 大小、…

LWN: 5.17 合并窗口第一部分!

关注了就能看到更多这么棒的文章哦&#xff5e; 5.16 Merge window, part 1 By Jonathan CorbetNovember 4, 2021DeepL assisted translationhttps://lwn.net/Articles/874683/ 截止到撰写此文的时候&#xff0c;Linus Torvalds 已经为 5.16 版本内核而向内核合入了 6800 个 no…

Linux出现Read-only file system错误解决方法

执行命令时遇到如下错误 这个问题是文件系统受损导致得&#xff0c;fstab文件未正确配置 解决方法&#xff1a; df -hT  #查看一下分区及挂载信息 fsck -a /dev/sda3  -a &#xff1a;检查文件系统&#xff0c;有异常便自动修复 执行完毕之后重启服务器 reboot 进入服务器&…

只需 6 步,你就可以搭建一个云原生操作系统原型

编者按&#xff1a;过去的三年对基础软件领域来说是不平凡的三年&#xff0c;是波涛汹涌的三年。随着国际形势和行业格局的变化&#xff0c;大家一定充分感受到了云原生和操作系统这两个话题的热度。那么当云原生和操作系统这两个热点话题相遇的时候&#xff0c;会发生什么故事…

Linux 内核源代码情景分析(四)

系列文章目录 Linux 内核设计与实现 深入理解 Linux 内核 Linux 设备驱动程序 Linux设备驱动开发详解 深入理解Linux虚拟内存管理 Linux 内核源代码情景分析&#xff08;一&#xff09; Linux 内核源代码情景分析&#xff08;二&#xff09; Linux 内核源代码情景分析&#xff…

TWS蓝牙耳机推荐哪个?2022国产无线蓝牙耳机推荐

随着各大手机厂商逐渐取消了传统的耳机插孔后&#xff0c;就有越来越多的人开始使用蓝牙耳机了。即使是过去一直觉得蓝牙耳机不太实用&#xff0c;最后也无法摆脱“真香理论”&#xff01;&#xff01;在蓝牙技术的快速发展的今天&#xff0c;蓝牙耳机在连接性能和音质方面取得…

女生小清新高颜值蓝牙耳机分享,低延迟高性价比TWS蓝牙耳机推荐

在电子竞技空前火热的今天,玩家对于游戏耳机的要求不仅仅停留在能听见声音的层面。特别是目前比较火热的射击类游戏对于游戏耳机的要求更加高,一款出色的游戏耳机可以让玩家在战场上“如虎添翼”,不仅如此,对于玩家而言,游戏时间基本两三个小时起步,因此长期佩戴的舒适性…

真无线蓝牙耳机什么牌子好?TWS蓝牙耳机推荐

蓝牙耳机的形态可以说是多种多样了&#xff0c;随着时代的发展&#xff0c;蓝牙耳机变成了我们不可或缺的东西&#xff0c;左右耳两只小小的耳机&#xff0c;搭配一个耳机仓。整个过程仅需要打开蓝牙就行&#xff0c;非常方便。那么在蓝牙耳机的带领下&#xff0c;什么款式的蓝…

2022TWS蓝牙耳机推荐,盘点600元真无线蓝牙耳机

近年来&#xff0c;随着蓝牙技术的发展和续航能力的提升&#xff0c;蓝牙耳机开始进入了"真"无线时代。在短短的几年内&#xff0c;TWS耳机成为了大家竞相占领的重要“城池”&#xff0c;各类蓝牙耳机如雨后春笋般出现。今天就来说说被各大网友推荐上榜单的音质好的蓝…

TWS蓝牙耳机哪些品牌好?TWS蓝牙耳机品牌排行榜

或许有很多人在挑选蓝牙耳机时候有所困扰&#xff0c;因为有一些蓝牙耳机动辄上千元&#xff0c;对于预算不足&#xff0c;对我朋友来说实在是头疼。每个人的需求不同&#xff0c;所以在挑选蓝牙耳机时候也会有所侧重。推荐几款平价蓝牙耳机&#xff0c;不足千元的价格&#xf…

PT2050(TWS 蓝牙耳机二合一触摸 IC)

1. 产品概述 PT2050 是一款应用于双入耳检测或单入耳检测的 TWS 蓝牙耳机二合一触摸检测芯片。该芯片内建稳压电路&#xff0c;提供稳定电压给触摸感应电路使用&#xff0c;同时内部集成高效完善的触摸检测算法&#xff0c;使得芯片具有稳定的触摸检测效果&#xff0c;具有宽工…

2021年TWS蓝牙耳机哪个好?tws蓝牙耳机排名!

自从各大手机取消了3.5mm耳机孔后&#xff0c;随身音频行业的发展速度就相当快&#xff0c;因此&#xff0c;TWS蓝牙耳机成为了更普遍的选择。越来越多的厂家也都涉足到这一领域&#xff0c;使得大家的选择越来越丰富&#xff0c;可谓乱花渐欲迷人眼&#xff0c;那么多的耳机&a…