vue3+element-plus 封装高度搜索组件,支持多种类型

目录

一、应用场景

二、开发流程

三、详细开发流程

1.新建文件

2.开始步骤

3.详细代码

(1).index.vue

(2).搜索组件

(3).单个搜索组件

总结


一、应用场景

一般很多网站,有很多数据列表,基本都要做搜索的功能,如果涉及很多页面,很多列表,那么搜索组件,一般要求统一样式之类的,并且封装搜索组件主要目的是提高代码的可维护性、可复用性和可扩展性,毕竟系统越写越多,列表页越来越多,不得不封装了,比如你看我这参与的项目,就从一开始的十几个页面,变成现在路由表快1000行的大项目,引用搜索组件的地方也高达:

问癌,它说,封装搜索组件的意义:

  1. 代码复用性: 封装搜索组件允许你在多个页面或组件中重复使用相同的搜索功能。这减少了代码的冗余,提高了开发效率。

  2. 可维护性: 通过将搜索功能封装到一个独立的组件中,可以更容易地维护和更新搜索逻辑。如果需要对搜索功能进行修改或添加新的功能,你只需要更新搜索组件而不必修改每个使用它的页面或组件。

  3. 可扩展性: 封装的搜索组件通常可以轻松扩展以支持不同类型的搜索字段或过滤条件。这使得在不同页面或应用中实现不同的搜索需求变得更加容易。

  4. 统一风格和用户体验: 通过使用相同的搜索组件,你可以确保整个应用的搜索界面保持一致的风格和用户体验,提高了应用的整体质量。

  5. 降低开发成本: 封装搜索组件可以节省开发时间和开发资源。开发人员可以专注于构建具体的业务逻辑而不必重复编写搜索功能。

  6. 易于测试: 独立的搜索组件可以更容易地进行单元测试,确保搜索功能的稳定性和正确性。

  7. 降低错误率: 通过减少手动编码搜索功能的机会,封装搜索组件有助于减少潜在的错误和bug。


二、开发流程

首先要明白,封装搜索组件,组件里都有什么,我这里封装的组件支持:

1.输入框

2.单选/多选/多选搜索/多选的远程搜索

3.时间选择器

通过form表单进行上面的封装

如下:

实现的效果,大概如此:

因为要考虑布局,所以使用的是col来控制布局,基本上一行放3个搜索框,加一组按钮,按钮有常见的查询,重置,折叠/展开,以及最右侧的业务按钮,比如:导出

上面的例子里,有几种类型(下面详细流程里有大图):

1.医生信息:el-input 输入框

2.所属医院:多选,带搜索和远程搜索(是否可以搜索、可以远程搜索、远程搜索的接口、传参、选项列表、选项的配置、是否能全选等自定义功能

3.患者id:输入框

4.患者状态:多选(单选、可清空)

5.创建时间:日期时间选择器 (显示默认时间:默认是最近7天、时间选择范围:如不能超过180天、在此日期之前的时间禁止选中)

接下来的开发过程都是以上面的图片为例子实现。 


三、详细开发流程

这里根据上面的例子封装一个搜索组件:

1.新建文件

(1)index.vue  需要引用搜索组件的页面

(2)src\components\searchOptionsBox.vue  这是外层的表单

(3)src\components\searchOptionItem.vue  这是单个组件的文件

2.开始步骤

先建一个空页面,随便写点东西,index.vue 里作为需要引入搜索组件的地方,先引入:

import SearchOptionsBox from '@/components/searchOptionsBox.vue'页面
<el-row><SearchOptionsBox  />
</el-row>

先考虑父组件,通常都是在父组件写查数据的操作,那么就需要拿到搜索的值,①输入文字,点击搜索后,进行查询,②点击重置,这些搜索的值都是空的,③再输入值,再搜索,那么再次搜索。

所以,父组件基本上,就需要给搜索组件传一些组件的配置和获取搜索的值的操作,至于其他的控制搜索组件的一些配置,那就另外加。

基础的是这些:

<SearchOptionsBox :search-options="searchOptions" @search="searchData" />

特殊的配置如下:

<SearchOptionsBox:search-options="searchOptions":show-button="true":btn-loading="btnLoading"button-name="导出":buttons-span="7"@search="searchData"/>

 这些特殊的配置,分别是控制,是否显示按钮组最右边的按钮,以及按钮的名字,按钮组占据的宽度比例

3.详细代码

(1).index.vue

const searchOptions = ref([{label: '医生信息',prop: 'doctor_info',inputType: 'String',optionType: 'input',placeHolder: '请输入医生信息'},{label: '所属医院',prop: 'hospital_id', //传arrayinputType: 'Array',optionType: 'select',multiple: true,isRemote: true, //远程搜索remoteSelectUrl: '/hospital-list',remoteParams: {disease_id: '...'},placeHolder: '请搜索或选择',selectOptions: [],selectLabel: 'center_name',selectValue: 'center_id'},{label: '患者id',prop: 'patient_id',inputType: 'String',optionType: 'input',placeHolder: '请输入患者id'},{label: '患者状态',prop: 'patient_status',inputType: 'Array',optionType: 'select',multiple: true,placeHolder: '请选择患者状态',selectOptions: [{ label: '住院', value: 1 },{ label: '出院', value: 2 },{ label: '其他', value: 3 }]},{label: '创建时间',prop: 'create_at',inputType: 'Array',optionType: 'datePicker',placeHolder: ''}
])let searchParams = reactive({})
const searchData = (searchForm) => {params.page = 1searchParams = JSON.parse(JSON.stringify(searchForm))  ///深拷贝if (searchForm.patient_status) {   //如果是get请求,为了业务就数组转存为string了searchParams.patient_status = JSON.stringify(searchParams.patient_status)}getDataList() //获取数据,searchParams是搜索的值
}//在获取数据时,把传参拼接一下
//let tempParams = { ...params, ...searchParams }

这个页面,主要定义一些搜索组件的配置,和搜索时的参数处理。

弊端是:会出现一些不必要的参数,比如一些没有值的参数也会传,当然可以清掉。

如果有导出功能,那么需要按照上面的特殊配置进行,同时,获取数据时,需要另外处理,如下:

let searchParams = ref({})
const searchData = (searchForm, download) => {params.page = 1searchParams.value = JSON.parse(JSON.stringify(searchForm))//post 接口可以直接传array,不用再次处理if (!download) {download = 0//或者false,这里我是以1代表trueisSearch.value = true} else {isDownload.value = true}
//获取数据时
}

 这里是详细的数据。

还有一个注意点,如果搜索组件的配置,有些比如多选组件,那么它的列表需要调接口才能拿到,要控制好页面加载的生命周期,一定要拿到数据再去加载搜索组件。

(2).搜索组件

首先,因为我懒得布局,所以就借用的form和col的布局方式,外层一个表单,每一个组件就是一个item,然后一个组件在col里用24布局,默认一个占6的大小,当然个别的可以调整,只要一行最大24就行,如此,一行也就能放3个组件一个按钮组,那么肯定要考虑折叠展开的逻辑,所以会有第二行,第三行,不过我的业务不涉及第三行,一般就两行。布局就大概这样。

这个页面详细的代码如下:

<template><div class="search-component"><el-form ref="searchFormRef" :inline="true" :model="searchForm" class="demo-form-inline" label-position="left"><!-- 一行分为四部分,可以换行,控制折叠的选项 --><el-row class="first-row"><el-col:span="option.span ? option.span : option.optionType == 'input' ? 6 : option.optionType == 'select' ? 5 : 7"v-for="(option, index) in firstFormOptions.splice(0, 3)":key="index"><el-form-item :label="option.label" :prop="option.prop" style="width: 100%; margin-right: 10px"><SearchOptionItem:placeHolder="option.placeHolder":prop="option.prop":inputType="option.inputType":optionType="option.optionType":isDefaultTime="option.isDefaultTime":timeRangeDays="option.timeRangeDays":disabledTime="option.disabledTime":multiple="option.multiple":disabled="option.disabled":isRemote="option.isRemote":remoteSelectUrl="option.remoteSelectUrl":remoteParams="option.remoteParams":searchField="option.searchField":ifParamsChange="option.ifParamsChange":nowRemoteParams="props.nowRemoteParams":selectOptions="option.selectOptions":selectAll="option.selectAll":selectLabel="option.selectLabel":selectValue="option.selectValue":value="searchForm[option.prop]"@returnValue="getValue"style="margin-right: 10px"/></el-form-item></el-col><el-col :span="searchOptions.length == 2 ? 12 : props.buttonsSpan"><el-form-item style="width: 100%"><div class="button-container"><div><el-button class="ml-1" type="primary" :icon="Search" @click="search">查询</el-button><el-button @click="resetForm(searchFormRef)">重置</el-button><el-button v-if="searchOptions.length > 3 && !isExpanded" link type="primary" @click="toggle">展开&nbsp;<el-icon><ArrowDownBold /></el-icon></el-button><el-button v-else-if="searchOptions.length > 3" link type="primary" @click="toggle">收起&nbsp;<el-icon><ArrowUpBold /></el-icon></el-button></div><el-button v-if="showButton" :loading="btnLoading" @click="clickButton" type="primary">{{ buttonName }}</el-button></div></el-form-item></el-col></el-row><el-row v-if="isExpanded && searchOptions.length > 3" class="second-row"><el-col:span="option.span || option.optionType == 'input' ? 6 : option.optionType == 'select' ? 5 : 7"v-for="(option, index) in secondFormOptions":key="index"><el-form-item :label="option.label" :prop="option.prop" style="width: 100%"><SearchOptionItem:placeHolder="option.placeHolder":prop="option.prop":inputType="option.inputType":optionType="option.optionType":isDefaultTime="option.isDefaultTime":timeRangeDays="option.timeRangeDays":disabledTime="option.disabledTime":multiple="option.multiple":disabled="option.disabled":isRemote="option.isRemote":remoteSelectUrl="option.remoteSelectUrl":remoteParams="option.remoteParams":searchField="option.searchField":ifParamsChange="option.ifParamsChange":nowRemoteParams="props.nowRemoteParams":selectOptions="option.selectOptions":selectAll="option.selectAll":selectLabel="option.selectLabel":selectValue="option.selectValue":value="searchForm[option.prop]"@returnValue="getValue"style="margin-right: 10px"/></el-form-item></el-col></el-row></el-form></div>
</template>

模块代码中,没有复杂的逻辑,都是给SearchOptionItem传一些数据的。

主要是SearchOptionItem需要的数据结构,都需要什么配置,需要在这个页面都传过去,就如上面index.vue里配置的那样。

js部分如下:


<script setup>
import { ref, reactive, watch, computed, onMounted, defineProps, defineEmits } from 'vue'
import { Search } from '@element-plus/icons-vue'
import SearchOptionItem from './searchOptionItem.vue'
import { getFormattedTime } from '@/utils/validate'//changeRemoteParams  用于更新远程搜索的字段
const emit = defineEmits(['search', 'changeRemoteParams'])
const props = defineProps({searchOptions: {default: [{label: '搜索',prop: 'search',inputType: 'String',optionType: 'input',placeHolder: '请输入关键字'},{label: '中心名称',prop: 'center_name',inputType: 'Array',//组件绑定值的类型optionType: 'select', //组件类型multiple: true, //是否多选span: 6, // 占据宽度isRemote: true,remoteSelectUrl: '', //远程搜索的接口remoteParams: {search: '',  disease_id: ''  //接口传参},disabled: false,searchField: '', //搜索时传的字段名placeHolder: '请选择中心',selectLabel: 'center_name',  //option的LabelselectValue: 'center_id',selectAll: false,  //是否能全选,自定义的功能selectOptions: [  //搜索选项{ label: '筛选中', value: 1 },{ label: '在组', value: 2 },{ label: '已出组', value: 3 }]},{label: '时间范围',prop: 'create_at',inputType: 'Array',optionType: 'datePicker',placeHolder: '',isDefaultTime: true, //显示默认时间,默认是最近7天timeRangeDays: 180, //时间选择范围,不能超过180天disabledTime: '2023-06-20' //在此日期之前的时间禁止选中}],type: Array},showButton: {default: false,type: Boolean},btnLoading: {default: true,type: Boolean},buttonName: { default: '导出', type: String },labelPosition: {default: 'right',type: String},//新参数nowRemoteParams: {  // 远程搜索的新参数,适配不同业务需要default: null,type: Object},//按钮组占据的宽度buttonsSpan: {default: 6,type: Number},// 用于初始化搜索框的值searchFormValue: {default: null,type: Object}
})const isExpanded = ref(false)
//搜索选项form数据
const searchForm = ref({})
const firstFormOptions = ref([]) //第一行选项框
const secondFormOptions = ref([]) //折叠的选项框onMounted(() => {//初始化搜索选项的值props.searchFormValue ? (searchForm.value = props.searchFormValue) : ''//根据数组的长度,判断显示的字段,前三个和后面折叠的多个firstFormOptions.value = JSON.parse(JSON.stringify(props.searchOptions)).splice(0, 3) || props.searchOptionssecondFormOptions.value = JSON.parse(JSON.stringify(props.searchOptions)).splice(3) || props.searchOptions
})const searchFormRef = ref(null)
const timeRanges = ref([])//处理数据
const getValue = (value, prop, optionType, ifParamsChange) => {//删除没有数据的选项字段if (optionType == 'datePicker') {  //时间选择器,这里的数据处理是根据业务需求写的if (value === null) {deleteDate()} else {searchForm.value.start_time = getFormattedTime(value[0]) //格式化时间searchForm.value.end_time = getFormattedTime(value[1])}} else if (!value && value !== 0) {  //如果数据为空就删掉这个属性delete searchForm.value[prop]} else {searchForm.value[prop] = value}if (ifParamsChange) { //如果数据改变了,就更新一下index.vue里的值emit('changeRemoteParams', searchForm.value[prop])}
}const search = (download) => {emit('search', searchForm.value, 0)
}const clickButton = () => {emit('search', searchForm.value, 1)
}const resetForm = (formEl) => {searchForm.value = {}deleteDate()
}const deleteDate = () => {delete searchForm.value.start_timedelete searchForm.value.end_time//清空项目名称的值,找到为时间选择器的值,全部清空props.searchOptions.forEach((item) => {if (item.optionType == 'datePicker') {searchForm.value[item.prop] = []}})
}
const toggle = () => {isExpanded.value = !isExpanded.value
}
</script>

具体的逻辑都在上面,有注释,大部分是跟业务有关的 

下面是我自定的样式,可以跳过。

.search-component {width: 100%;.el-form--inline .el-form-item {margin-right: 10px;}:deep(.el-form-item__label) {font-weight: bold !important;}.first-row {display: flex;flex-direction: row;flex-wrap: nowrap;.el-col {height: 32px !important;}}.second-row {display: flex;flex-direction: row;flex-wrap: nowrap;margin-top: 10px;.el-col {height: 32px !important;}}.option-container {width: 25%;}.button-container {width: 100%;display: flex;justify-content: space-between;}.el-button + .el-button {margin-left: 10px;}
}.select-item {.el-select .el-select-tags-wrapper.has-prefix {display: flex;max-width: 70% !important; //设置最大宽度 超出显示...flex-wrap: nowrap;}.el-tag.is-closable {// width: 45%;// max-width: 70px;}.el-select__tags .el-tag:last-child {// width: 45%;// max-width: 70px;}.el-tag__content {width: 100%;}.el-select .el-select__tags-text {max-width: 45px !important; //设置最大宽度 超出显示...display: inline-block;overflow: hidden;vertical-align: bottom;text-overflow: ellipsis;}.el-select__input {margin-left: 5px;}
}</style>

(3).单个搜索组件

 页面是三个判断,就根据不同的类型,进行不同的配置,现在页面的类型还比较少,还不卡,后面越来越多,可能不友好吧。

<template><div class="item-container"><div v-if="optionType == 'input'" class="input-item"><el-input v-model="inputValue" :placeholder="placeHolder" clearable @change="returnValue" @clear="returnValue" /></div><div v-if="optionType == 'datePicker'" class="date-picker-item"><el-date-pickerv-model="timeRange"type="datetimerange":shortcuts="shortcuts":disabled-date="disabledDate":default-time="defaultTime"placeholder="请选择日期"format="YYYY-MM-DD HH:mm:ss"range-separator="至"start-placeholder="开始日期"end-placeholder="结束日期"@change="chooseData"@clear="chooseData"style="width: 100%"/></div><div v-if="optionType == 'select'" class="select-item"><el-selectv-model="inputValue":placeholder="placeHolder"style="width: 100%"clearable:filterable="isRemote":remote="isRemote":remote-method="selectRemoteMethod":loading="selectLoading":multiple="multiple":collapse-tags="multiple":disabled="disabled"@clear="returnValue"@change="returnValue"@visible-change="openChange"><el-option v-if="selectAll" key="all" label="全选" value="all" /><el-optionv-for="item in newSelectOptions":key="item[props.selectValue]":label="item[props.selectLabel]":value="item[props.selectValue]"/></el-select></div></div>
</template>

这里面绑定的值,value是从上个页面传来的,因为不能改,所以用新的值代替了。

 

<script setup>
import { ref, reactive, computed, onMounted, defineProps, defineEmits } from 'vue'
import { ElMessage } from 'element-plus'const emit = defineEmits(['returnValue'])
const props = defineProps({prop: {default: '',type: String},placeHolder: {default: '',type: String},inputType: {// 字段类型,String,Arraydefault: 'String',type: String},optionType: {//选择的类型:input,select,datePickerdefault: 'input',type: String},//多选框的选项selectOptions: {default: [{ label: '是', value: 1 }],type: Array},// 多选框是否多选multiple: {default: true,type: Boolean},disabled: { //是否禁用default: false,type: Boolean},//选择器是否远程搜索isRemote: {default: false,type: Boolean},//远程搜索的地址remoteSelectUrl: {default: '',type: String},//远程搜索需要的参数remoteParams: {default: { search: '', disease_id: '' },type: Object},//远程搜索需要的参数是否会发生改变,比如审核任务效率统计的页面里研究者中的项目idifParamsChange: {default: false,type: Boolean},//新参数,需要替换nowRemoteParams: {default: { search: '', disease_id: [] },type: Object},//远程搜索时的字段,默认是searchsearchField: {default: 'search',type: String},//远程搜索获取的列表的label和valueselectLabel: {default: 'label',type: String},selectValue: {default: 'value',type: String},//是否显示全选selectAll: {default: false,type: Boolean},//是否显示默认时间,默认是最近7天,进入页面时,请求时参数未传入,只是显示isDefaultTime: {default: false,type: Boolean},//时间选择范围,不能超过180天timeRangeDays: {default: null,type: Number},//在此日期之前的时间禁止选中disabledTime: {default: '',type: String},//绑定的值value: {}
})
watch(() => props.value,(newValue, oldValue) => {inputValue.value = props.valuetimeRange.value = props.value},() => props.selectOptions,(newValue, oldValue) => {newSelectOptions.value = props.selectOptions},() => props.nowRemoteParams, // 自定义的功能,可以不看(newValue, oldValue) => {if (props.prop == 'researcher') {params = { ...tempParams, ...props.nowRemoteParams }} else {params = { ...tempParams, ...props.remoteParams }}}
)const inputValue = ref(null)
const timeRange = ref([])
const newSelectOptions = ref(null) //新的选项配置
const shortcuts = [{text: '最近一周',value: () => {const end = new Date()const start = new Date()start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)return [start, end]}},{text: '最近一个月',value: () => {const end = new Date()const start = new Date()start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)return [start, end]}},{text: '最近三个月',value: () => {const end = new Date()const start = new Date()start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)return [start, end]}},{text: '最近半年',value: () => {const end = new Date()const start = new Date()start.setTime(start.getTime() - 3600 * 1000 * 24 * 180)return [start, end]}}
]const defaultTime = reactive([new Date(0, 0, 0, 0, 0, 0), new Date(0, 0, 0, 23, 59, 59)])onMounted(() => {inputValue.value = props.valuenewSelectOptions.value = props.selectOptionsif (props.isRemote) {getOPtions('') //先默认获取选项列表}//设置默认时间为最近七天if (props.optionType == 'datePicker') {timeRange.value = props.isDefaultTime ? [getStartDate(), getEndDate()] : props.value}
})
const getStartDate = () => {const endDate = new Date() // 当前日期const startDate = new Date()startDate.setDate(endDate.getDate() - 6) // 最近七天的开始日期return startDate
}const getEndDate = () => {const endDate = new Date() // 当前日期return endDate
}const selectLoading = ref(false)
const selectRemoteMethod = (value) => {//远程搜getOPtions(value)
}//这是为了处理,多选远程搜索时,输入框聚焦就能显示选项
const openChange = (open, value) => {let valueLength = inputValue.value ? inputValue.value.length : 0if (open && valueLength == 0 && props.isRemote) {getOPtions('')}
}
let params = reactive({})
const getOPtions = async (value) => {// 搜索的字段,可更改,根据业务需求来的let tempParams = {}tempParams[props.searchField] = valueif (props.prop == 'researcher') {params = { ...tempParams, ...props.nowRemoteParams }} else {params = { ...tempParams, ...props.remoteParams }}selectLoading.value = truenewSelectOptions.value = []let res = (await axios.get(props.remoteSelectUrl, {params: params})).dataif (res.code == 200) {if (res.data.length > 0) {newSelectOptions.value = res.data}selectLoading.value = false} else {ElMessage.error(res.message || '搜索失败!')}
}//往上个页面emit数据
const returnValue = (val) => {// 若全选if (props.selectAll && val.some((el) => el == 'all')) {inputValue.value = newSelectOptions.value.map((item) => item[props.selectValue])}emit('returnValue', inputValue.value, props.prop, props.optionType, props.ifParamsChange)
}//emit 时间
const returnData = () => {emit('returnValue', timeRange.value, props.prop, props.optionType)
}/**@target: 设置禁止选中的时间*@description: time不能在设置的默认日期前,如2023-06-20,该功能有些占性能,缺点之一*/
const disabledDate = (time) => {const selectedTime = time.getTime() // 选中时间// 限制日期范围在 disabledTime之前不能选if (props.disabledTime) {const minDate = new Date(props.disabledTime).getTime()return selectedTime < minDate} else {true}
}/**@target: 限制时间段范围*@description: time 不能与现在的时间间隔超过特定天数,如180天**/
// 进入页面的时候,时间显示但是搜索值里没有
const chooseData = () => {// 设置时间if (timeRange.value) {const startDate = timeRange.value[0] || ''const endDate = timeRange.value[1] || ''// 限制时间段在 180 天以内const intervalDays = Math.floor((endDate - startDate) / (24 * 60 * 60 * 1000))if (props.timeRangeDays && intervalDays > props.timeRangeDays) {// 超过特定天数,进行处理,重置日期范围并提示用户timeRange.value = nullElMessage.warning('时间范围不能超过180天,请重新选择')} else if (props.disabledTime && startDate < new Date(props.disabledTime)) {//在时间结构表里选择时间时,不能选择特定限制日期前的时间timeRange.value = nullElMessage.warning(`不支持选择${props.disabledTime}前的时间,请重新选择`)}}returnData()
}

逻辑都在上面,注释写的很详细。

很多都是自定义方法,因为跟业务有关。

这上面封装的是比较简单。

总结

总的来说,封装搜索组件有助于提高前端应用的开发效率、质量和可维护性,特别是在大型应用中或需要频繁使用搜索功能的情况下,封装搜索组件是一个明智的选择。

但是!

我写的感觉还是不要高级,很多配置都是在业务堆积的过程中,一点点添加的。希望下次写个可扩展性和维护性高的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/163957.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【CMN】Components组件汇总

CMN 700由各种类型的设备组成&#xff0c;包括路由器模块、CHI节点和网桥。所需要的组件取决于系统的需求&#xff0c;有些组件是可选的&#xff0c;或者只有在满足某些需求时才会使用。CMN 700可以集成到一个完整的SoC系统中&#xff0c;该系统还包括其他这里未描述到的设备。…

金融机器学习方法:K-均值算法

目录 1.算法介绍 2.算法原理 3.python实现示例 1.算法介绍 K均值聚类算法是机器学习和数据分析中常用的无监督学习方法之一&#xff0c;主要用于数据的分类。它的目标是将数据划分为几个独特的、互不重叠的子集或“集群”&#xff0c;以使得同一集群内的数据点彼此相似&…

Leetcode刷题详解——四数之和

1. 题目链接&#xff1a;四数之和 2. 题目描述&#xff1a; 给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若两个四元组元素一一对应&#xff0…

stm32 cubeide 闪退 显示self upgrade failed

更新或安装新版cubeide时&#xff0c;可能会出现打开后一段时间直接闪退&#xff0c;显示如下图。此时怎么折腾cubeide都是没用的。应该去升级stm32 cubemx。记得打开cubemx时选择用管理员身份打开&#xff0c;升级完成后重新开打。然后尝试打开cubdeide&#xff0c;如果继续报…

接口测试面试题整理​​​​​​​

HTTP, HTTPS协议 什么是DNSHTTP协议怎么抓取HTTPS协议说出请求接口中常见的返回状态码http协议请求方式HTTP和HTTPS协议区别HTTP和HTTPS实现机有什么不同POST和GET的区别HTTP请求报文与响应报文格式什么是Http协议无状态协议?怎么解决HTTP协议无状态协议常见的POST提交数据方…

《向量数据库指南》——向量数据库是小题大作的方案?

假设大语言模型需要 10 秒钟才能生成一条结果,即需要存储的单条新记忆。那么我们获得 10 万条记忆的时间周期将为:100000 x 10 秒 = 1000000 秒——约等于 11.57 天。而即使我们用最简单的暴力算法(Numpy 的点查询),整个过程也只需要几秒钟时间,完全不值得进行优化!也就…

微信小程序会议OA系统

Flex弹性布局 Flex弹性布局是一种 CSS3 的布局模式&#xff0c;也叫Flexbox。它可以让容器中的元素按一定比例自动分配空间&#xff0c;使得它们在不同宽度、高度等情况下仍能保持整齐和密集不间隙地排列。 在使用Flexbox弹性布局时&#xff0c;首先需要创建一个容器和若干个…

VSCode搭建ESP32 ESP-IDF开发环境-Windows

陈拓 2023/10/09-2023/10/14 1. 安装Windows系统下的ESP32 ESP-IDF开发环境 见《Windows系统安装ESP32 ESP-IDF开发环境》 Windows系统安装ESP32 ESP-IDF开发环境-CSDN博客Windows系统安装ESP32 ESP-IDF开发环境。https://blog.csdn.net/chentuo2000/article/details/1339225…

SpringMVC之全局异常拦截器

在SpringMVC自动装配核心类之WebMvcAutoConfiguration内部实例化EnableWebMvcConfiguration过程中会触发其父类WebMvcConfigurationSupport内部初始化HandlerExceptionResolver。 1.WebMvcConfigurationSupport public class WebMvcConfigurationSupport implements Applicat…

用户登录管理中的Bug修复与技术思考

目录 1 前言2 问题提出3 问题分析和解决4 技术分析和改进5 结语 1 前言 在开发管理软件平台为美术馆时&#xff0c;我们致力于提供一个多系统集成平台&#xff0c;其中包括艺术品管理、志愿者管理和数字资产管理等子系统。为了确保用户享有流畅的体验&#xff0c;我们采用了一…

volatile-两大特性(可见性、有序性)、内存屏障

6.1 被volatile修饰的变量有两大特点 ● 特点&#xff1a;○ 可见性○ 有序性&#xff1a;有排序要求&#xff0c;有时需要禁重排● 内存语义&#xff1a;○ 当写一个volatile变量时&#xff0c;JMM会把该线程对应的本地内存中的共享变量值立即刷新回主内存中○ 当读一个vola…

【小黑嵌入式系统第四课】嵌入式系统硬件平台(二)——I/O设备、通信设备(UARTUSB蓝牙)、其他(电源时钟复位中断)

上一课&#xff1a; 【小黑嵌入式系统第三课】嵌入式系统硬件平台&#xff08;一&#xff09;——概述、总线、存储设备&#xff08;RAM&ROM&FLASH) 文章目录 一、I/O设备1. 定时器/计数器2. ADC和DAC3. 人机接口设备3.1 键盘3.2 LCD显示器3.3 触摸屏 二、通信设备1. 通…

京东店铺公司名爬虫

内容仅供学习参考&#xff0c;如有侵权联系删除 先通过京东非自营的店铺名拿到的公司名&#xff0c;再通过公司名称去其他平台拿到联系方式&#xff08;代码省略&#xff09; from aioscrapy.spiders import Spider from aioscrapy.http import Request, FormRequest import dd…

Maven安装教程

目录 不喜欢废话&#xff0c;直接上教程&#xff01; 第一步&#xff1a;下载maven 第二步&#xff1a;环境配置 第三步&#xff1a;配置maven 配置maven包括配置本地仓库的位置&#xff0c;配置镜像&#xff0c;配置JDK&#xff0c;都在settings.xml里面配置 配置本地仓…

互联网Java工程师面试题·Java 总结篇·第九弹

目录 75、阐述 JDBC 操作数据库的步骤。 76、Statement 和 PreparedStatement 有什么区别&#xff1f;哪个性 能更好&#xff1f; 77、使用 JDBC 操作数据库时&#xff0c;如何提升读取数据的性能&#xff1f;如何提升更新数据的性能&#xff1f; 78、在进行数据库编程时&a…

卷积神经网络手写字符识别 - 深度学习 计算机竞赛

文章目录 0 前言1 简介2 LeNet-5 模型的介绍2.1 结构解析2.2 C1层2.3 S2层S2层和C3层连接 2.4 F6与C5层 3 写数字识别算法模型的构建3.1 输入层设计3.2 激活函数的选取3.3 卷积层设计3.4 降采样层3.5 输出层设计 4 网络模型的总体结构5 部分实现代码6 在线手写识别7 最后 0 前言…

【Solution】商品秒杀之Redis缓存与MQ异步优化以及超卖一人一单等问题的解决

目录 一、Demo开始前准备 1、数据库准备 2、项目准备 3、全局唯一id生成器 二、秒杀业务基本实现 1、秒杀基本业务逻辑 2、秒杀接口设计 3、秒杀业务代码实现 4、超卖问题产生 三、保证线程安全解决超卖少卖问题 1、超卖产生的原因 2、加锁方案&#xff1a;乐观锁 …

基于SSM的传统文化网站

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

使用Portainer图形化工具轻松管理远程Docker环境并实现远程访问

文章目录 前言1. 部署Portainer2. 本地访问Portainer3. Linux 安装cpolar4. 配置Portainer 公网访问地址5. 公网远程访问Portainer6. 固定Portainer公网地址 前言 Portainer 是一个轻量级的容器管理工具&#xff0c;可以通过 Web 界面对 Docker 容器进行管理和监控。它提供了可…

【C/PTA】顺序结构专项练习

本文结合PTA专项练习带领读者掌握顺序结构&#xff0c;刷题为主注释为辅&#xff0c;在代码中理解思路&#xff0c;其它不做过多叙述。 7-1 是不是太胖了 据说一个人的标准体重应该是其身高&#xff08;单位&#xff1a;厘米&#xff09;减去100、再乘以0.9所得到的公斤数。已…