uniapp实战教程:如何封装一个可复用的表单组件

在uniapp开发过程中,表单组件的使用场景非常广泛。为了提高开发效率,我们可以将常用的表单组件进行封装。本文将带你了解如何在uniapp中封装一个表单组件,让你只需要通过属性配置轻松实现各种表单,效果图如下:

一、准备工作

在开始封装表单组件之前,请确保你已经掌握了以下知识:

        1、uniapp基础知识

        2、Vue.js基础知识

        3、组件通信与传值

二、分析需求

在封装表单组件之前,我们需要明确以下需求:

        1、支持多种表单元素(如:输入框、可下拉选择输入框、时间选择器、数字加减器、图片上传、下拉框等)

        2、支持自定义确认和取消按钮

        3、支持表单验证

        4、支持添加插槽

        5、支持表单数据提交

三、封装步骤

1、在uniapp项目的components目录下,创建一个名为customForm的文件夹,并在该文件夹下创建index.vue文件,文件代码如下:
<template><view><form @submit="formSubmit" @reset="formReset"><view v-for="(item, idx) in formConfig" :key="item.name"class="flex w-p-100 align-center row fz-17 relative"><view v-if="item.label" class="w-p-30">{{item.label}}</view><view v-if="item.require" class="inline-block absolute t-15 l-9 fz-18 text-red">*</view><!-- 输入框 --><input class="flex1 form-input" v-if="item.type=='input'" :placeholder="item.placeholder" :name="idx"v-model="data[idx]" :disabled="item.disabled" :type="item.inputType || 'text'"><!-- 下拉选择框 --><picker v-else-if="item.type=='picker'" @change="bindPickerChange" :data-index="idx":value="item.selectedIndex" :range="item.arrayData" :range-key="item.rangeKey" :name="idx"><input :value="item.rangeKey ? item.arrayData[item.selectedIndex]&&item.arrayData[item.selectedIndex][item.rangeKey] : item.arrayData[item.selectedIndex]"  disabled :placeholder="item.placeholder" class="uni-input" /></picker><!-- 时间选择 --><datePicker v-else-if="item.type=='datePicker'" :timeFormat="item.timeFormat"@datetimeChange="e => datetimeChange(e,idx)"></datePicker><!-- 图片上传 --><view v-else-if="item.type=='upLoad'" class="file-picker"><uni-file-picker :limit="item.limit" @select="e => handleSelect(e, item, idx)" @delete="e => deletePictrue(e, idx)":autoUpload="false" :value="data[idx]?[{url:data[idx]}]:''"></uni-file-picker></view><!-- 可下拉选择输入框 --><input-select class="flex1 fz-18" v-else-if="item.type == 'inputSelect'" :placeholder="item.placeholder":options="item.options" :value="data[idx]" @change="e => inputSelectChange(e, idx)"></input-select><!-- 数字加减器 --><view class="flex1 h-p-100 flex align-center" v-else-if="item.type == 'numberBox'"><uni-number-box @change="e => bindNumberChange(e, idx)" class="uni-number-box" :min="1"v-model="data[idx]" /></view><!-- 插槽 --><slot v-else-if="item.type == 'slot'" :name="item.slotName"></slot></view><view class="p-15"><button form-type="submit" type="primary">{{submitTxet}}</button><button v-if="reset" form-type="reset">{{resetText}}</button></view></form></view>
</template><script setup>import datePicker from '../datePicker/datePicker.vue';import {reactive,ref,watch,toRefs} from 'vue'import * as utils from '@/utils/index.js'const props = defineProps({reset: {type: Boolean,default: false},resetTxet: {type: String,default: '重置'},submitTxet: {type: String,default: '提交'},formConfig: {type: Object,required: true,default: () => {return {}}},resultData: {type: Object,default: () => {return {}}}})let data = reactive(props.resultData)// const pickerValue = ref('')const bindPickerChange = (e) => {let index = e.detail.value,idx = e.target.dataset.index,item = props.formConfig[idx]item.selectedIndex = indexdata[idx] = item.rangeKey ? item.arrayData[index][item.key || 'id'] : item.arrayData[index]}const handleSelect = (e, item, idx) => {if (item.success) {item.success(e, idx)} else {uploadSuccess(e, idx)}}const uploadSuccess = (e, idx) => {data[idx] = e.tempFilePaths[0]}const deletePictrue = (e, idx) => {data[idx] = ''}const datetimeChange = (e, idx) => {data[idx] = e.detail.valueStr}const inputSelectChange = (e, idx) => {data[idx] = e.detail.value}const bindNumberChange = (e, idx) => {data[idx] = e}const emit = defineEmits(['formSubmit'])const formSubmit = (e) => {let bool = utils.formVerify(data, props.formConfig)bool && emit('formSubmit', data)}
</script><style>.row {min-height: 90rpx;padding: 0 0 0 40rpx;box-sizing: border-box;border-bottom: 1px solid #ccc;}.file-picker {width: 264rpx;}.form-input {height: 90rpx;}
</style>
2、在父组件中使用:

父组件.vue文件中:

<template><view><customForm :formConfig="fromConfigRef" :resultData="resultData" submitTxet="确定" @formSubmit="formSubmit"></customForm></view>
</template><script setup>import {ref,reactive} from 'vue'import {fromConfig} from './fromConfig';
import {onLoad} from '@dcloudio/uni-app'import API from '@/api/index.js'const fromConfigRef = reactive(fromConfig)const resultData = reactive({})let statusIndex = nullonLoad(async(options) => {if(options.resultData) {let data = JSON.parse(decodeURIComponent(options.resultData)) // 更新响应式对象resultData的属性for (const key in data) {resultData[key] = data[key];}}statusIndex = options.statusIndexlet res = await API.SiteOrder.pullDownInstrumentName()fromConfigRef['factoryName'].options = res// console.log(fromConfigRef)})const formSubmit = (data) => {if(!data.number) {data.number = 1}const backData = {statusIndex,data}uni.navigateBack({delta: 1,success: () => {uni.$emit('pushData', backData)}})}
</script><style></style>

fromConfigRef.js配置文件:

export const fromConfig = {'factoryName':{label:'器具名称',type: 'inputSelect',placeholder: '请输入器具名称',options:[],require: true},'factoryFormat':{label:'器具规格',type: 'input',placeholder: '请输入器具规格',require: true},'factoryNo':{label:'器具编号',type: 'input',placeholder: '请输入器具编号'},'number':{label:'数量',type: 'numberBox'},'person':{label:'联系人',type: 'input',placeholder: '请输入联系人',require: true},'marks':{label:'备注',type: 'input',placeholder: '请输入备注',},
}

 

 

3、关于customForm组件的index.vue文件,有以下几点需要注意:
1、class样式

我采用了原子化css样式,所以在这个文件style中并没有太多的 样式 ,而是直接用了原子化css里面的class名,比如:class="flex",表示display:flex。原子化css文件已给出。

2、自定义组件

组件中datePicker、input-select为另外封装的自定义组件,主要实现了日期时间选择和可输入可选择下拉框。

datePicker.vue组件文件如下,如需要可自取:

<template><view style="height: 100%"><picker mode="multiSelector" :value="dateTime" @change="changeDateTime" @columnchange="changeDateTimeColumn" :range="dateTimeArray"><view class="weui-input"><block v-if="timeFormat == 'YYYY-MM-DD HH:mm'">{{ dateTimeArray && dateTimeArray[0][dateTime[0]] }}-{{ dateTimeArray && dateTimeArray[1][dateTime[1]] }}-{{ dateTimeArray && dateTimeArray[2][dateTime[2]] }} {{ dateTimeArray && dateTimeArray[3][dateTime[3]] }}:{{dateTimeArray && dateTimeArray[4][dateTime[4]]}}</block><block v-else>{{ dateTimeArray && dateTimeArray[0][dateTime[0]] }}-{{ dateTimeArray && dateTimeArray[1][dateTime[1]] }}-{{ dateTimeArray && dateTimeArray[2][dateTime[2]] }} {{ dateTimeArray && dateTimeArray[3][dateTime[3]] }}:{{dateTimeArray && dateTimeArray[4][dateTime[4]]}}:{{ dateTimeArray && dateTimeArray[5][dateTime[5]] }}</block></view></picker></view>
</template><script>
import * as utils from '@/utils/index.js'
export default {name:'datePicker',data() {return {dateTimeArray: null,//时间年月日时分秒数组dateTime: null,//选中的年月日时分秒每个数组的下标startYear: 1900,//起始年份endYear: 2200 //结束年份};},/*** 组件的属性列表*/props: {value: {type: String,default: ''},//默认值,不传为当前时间timeFormat: {type: String,default: 'YYYY-MM-DD HH:mm:ss'} //时间格式 YYYY-MM-DD HH:mm:ss 和 YYYY-MM-DD HH:mm两种},/*** 组件的方法列表*/methods: {attached() {//初始化var obj = utils.dateTimePicker(this.startYear, this.endYear, this.value);if (this.timeFormat == 'YYYY-MM-DD HH:mm') {//如果是精准到分,则去掉分的数据obj.dateTimeArray.pop();}this.dateTime = obj.dateTime;this.dateTimeArray = obj.dateTimeArray//将初始化后的时间值返回给绑定的valuelet dateTime = '';let dateTimeStr = '';if (this.timeFormat == 'YYYY-MM-DD HH:mm') {dateTime =this.dateTimeArray[0][this.dateTime[0]] +'-' +this.dateTimeArray[1][this.dateTime[1]] +'-' +this.dateTimeArray[2][this.dateTime[2]] +' ' +this.dateTimeArray[3][this.dateTime[3]] +':' +this.dateTimeArray[4][this.dateTime[4]];dateTimeStr =this.dateTimeArray[0][this.dateTime[0]] +'-' +this.dateTimeArray[1][this.dateTime[1]] +'-' +this.dateTimeArray[2][this.dateTime[2]] +'T' +this.dateTimeArray[3][this.dateTime[3]] +':' +this.dateTimeArray[4][this.dateTime[4]] +':00.000Z';} else {dateTime =this.dateTimeArray[0][this.dateTime[0]] +'-' +this.dateTimeArray[1][this.dateTime[1]] +'-' +this.dateTimeArray[2][this.dateTime[2]] +' ' +this.dateTimeArray[3][this.dateTime[3]] +':' +this.dateTimeArray[4][this.dateTime[4]] +':' +this.dateTimeArray[5][this.dateTime[5]];dateTimeStr =this.dateTimeArray[0][this.dateTime[0]] +'-' +this.dateTimeArray[1][this.dateTime[1]] +'-' +this.dateTimeArray[2][this.dateTime[2]] +'T' +this.dateTimeArray[3][this.dateTime[3]] +':' +this.dateTimeArray[4][this.dateTime[4]] +':' +this.dateTimeArray[5][this.dateTime[5]] +'.000Z';}this.$emit('datetimeChange', {detail: {value: dateTime,valueStr: dateTimeStr}});},changeDateTime(e) {this.dateTime = e.detail.valuelet dateTime = '';let dateTimeStr = '';if (this.timeFormat == 'YYYY-MM-DD HH:mm') {dateTime =this.dateTimeArray[0][this.dateTime[0]] +'-' +this.dateTimeArray[1][this.dateTime[1]] +'-' +this.dateTimeArray[2][this.dateTime[2]] +' ' +this.dateTimeArray[3][this.dateTime[3]] +':' +this.dateTimeArray[4][this.dateTime[4]];dateTimeStr =this.dateTimeArray[0][this.dateTime[0]] +'-' +this.dateTimeArray[1][this.dateTime[1]] +'-' +this.dateTimeArray[2][this.dateTime[2]] +'T' +this.dateTimeArray[3][this.dateTime[3]] +':' +this.dateTimeArray[4][this.dateTime[4]] +':00.000Z';} else {dateTime =this.dateTimeArray[0][this.dateTime[0]] +'-' +this.dateTimeArray[1][this.dateTime[1]] +'-' +this.dateTimeArray[2][this.dateTime[2]] +' ' +this.dateTimeArray[3][this.dateTime[3]] +':' +this.dateTimeArray[4][this.dateTime[4]] +':' +this.dateTimeArray[5][this.dateTime[5]];dateTimeStr =this.dateTimeArray[0][this.dateTime[0]] +'-' +this.dateTimeArray[1][this.dateTime[1]] +'-' +this.dateTimeArray[2][this.dateTime[2]] +'T' +this.dateTimeArray[3][this.dateTime[3]] +':' +this.dateTimeArray[4][this.dateTime[4]] +':' +this.dateTimeArray[5][this.dateTime[5]] +'.000Z';}this.$emit('datetimeChange', {detail: {value: dateTime,valueStr: dateTimeStr}});},changeDateTimeColumn(e) {var arr = this.dateTime;var dateArr = this.dateTimeArray;arr[e.detail.column] = e.detail.value;dateArr[2] = utils.getMonthDay(dateArr[0][arr[0]], dateArr[1][arr[1]]);this.dateTimeArray = dateArrthis.dateTime = arr}},mounted() {// 处理小程序 attached 生命周期this.attached();},created: function () {}
};
</script>
<style>
.icon-box-img {position: absolute;left: 5px;top: 8px;height: 10px;color: #ddd;
}
.weui-input {width: 200px;height: 2.5em;min-height: 2.5em;line-height: 2.5em;position: relative;border-radius: 3px;
}
</style>

input-select.vue组件代码如下,如需要可自取:

<template><view class="select-box"><view :class="isShow ? 'select-current-open' : 'select-current'" @tap.stop.prevent="openClose"><input @input="bindinput"  @blur="inputBlur" class="current-name" :placeholder="placeholder" v-model="inputValue" /></view><view class="option-list" v-if="isShow" @tap.stop.prevent="optionTap" style="overflow-y: auto; overflow-x: hidden; max-height: 200px"><text :data-index="index" :class="'option ' + (item.selection ? 'selection' : '')" v-for="(item, index) in result" :key="item.id">{{ item[label] }}</text></view></view>
</template><script>
export default {data() {return {result: [],//转换后的候选项数据selection: 'selection',//选中样式inputValue: '',//输入框的值isShow: false,index: null,// 选中的下标inputFocus: false //输入框是否有焦点};},props: {options: {type: Array,default: () => []},label: {type: String,default: 'name'},value: {type: String,default: ''},placeholder: {type: String,default: '请选择'}},watch: {//监听数据变化inputValue: function (value) {},options: function (value) {this.result = value},value: {handler(newValue, oldVal) {this.inputValue = newValue},immediate: true}},methods: {attached() {// 属性名称转换, 如果不是 { id: '', name:'' } 格式,则转为 { id: '', name:'' } 格式let result = [];if (this.key !== 'id' || this.text !== 'name' || this.text !== 'yes') {for (let item of this.options) {let { [this.key]: id, [this.text]: name, [this.selection]: selection } = item;result.push({id,name,selection});}}this.result = result},optionTap(e) {let that = this;let resuleObj = {flag: true}; //传递父组件的值.flag 表示是否是新增的 . true是新增,false不是新增this.index = e.target.dataset.index;this.inputValue = that.result[that.index][that.label]//选中的idvar id = this.result[this.index].id;for (var i = 0; i < this.options.length; i++) {if (this.options[i].id == id) {this.options[i].selection = true;resuleObj.id = this.options[i].id;resuleObj.flag = false;} else {this.options[i].selection = false;}}this.isShow = falsethis.result = this.optionsresuleObj.value = that.inputValue;//调用父组件方法,并传参this.$emit('change', {detail: resuleObj});},openClose() {//如果是获取到焦点的状况下,就不关闭下拉选项if (this.inputFocusFun && this.isShow) {return;}var that = this;this.isShow = !that.isShowif (!this.isShow) {this.closeSetInputValue();}//只要操作当前项,就是获取到当前项的焦点this.$emit('focus', {detail: {value: true}});},// 此方法供父组件调用close() {this.isShow = falsethis.closeSetInputValue();},closeSetInputValue() {//通过close和openClose方法隐藏选项时,设置inputValue的值let that = this;let inputValue = this.inputValue;//如果为空,直接返回if (!inputValue) {return;}//返回的数据结构let resuleObj = {flag: true};for (let i = 0; i < this.options.length; i++) {if (this.options[i][this.label] == inputValue) {this.options[i].selection = true;resuleObj.id = this.options[i].id;resuleObj.flag = false;} else {this.options[i].selection = false;}}resuleObj.value = that.inputValue;//调用父组件方法,并传参this.$emit('change', {detail: resuleObj});},inputFocusFun() {this.inputFocus = true},inputBlur() {this.inputFocus = false},bindinput(e) {var keyWord = e.detail.value;this.inputValue = e.detail.value;var tempresult = [];if (keyWord) {var obj = {id: -1};obj[this.label] = keyWord;tempresult.push(obj);}for (var i = 0; i < this.options.length; i++) {if (this.options[i][this.label] == keyWord) {this.options[i].selection = true;tempresult.push(this.options[i]);tempresult.splice(0, 1);continue;}if (this.options[i][this.label].indexOf(keyWord) != -1) {this.options[i].selection = false;tempresult.push(this.options[i]);}}this.result = tempresult}},mounted() {// 处理小程序 attached 生命周期this.attached();},created: function () {}
};
</script>
<style>
.select-box {position: relative;width: 100%;font-size: 17px;
}.select-current {position: relative;width: 100%;padding: 0 20px 0 6px;border: 1rpx solid #ddd;border-radius: 1px;box-sizing: border-box;line-height: 32px;
}.select-current::after {position: absolute;display: block;right: 10px;top: 15px;content: '';width: 0;height: 0;border: 4px solid transparent;border-top: 5px solid #999;
}.select-current-open {position: relative;width: 100%;padding: 0 20px 0 6px;border: 1rpx solid #ddd;border-radius: 1px;box-sizing: border-box;line-height: 32px;
}.select-current-open::after {position: absolute;display: block;right: 10px;top: 10px;content: '';width: 0;height: 0;border: 4px solid transparent;border-bottom: 5px solid #999;
}.selection {color: #00bbff;
}.current-name {display: block;width: 85%;height: 32px;word-wrap: normal;overflow: hidden;
}.option-list {position: absolute;font-size: 14px;left: 0;width: 100%;border-radius: 6rpx;box-sizing: border-box;z-index: 99;border: 1px solid #ddd;border-top: none;background-color: #fff;
}.option {display: block;width: 100%;line-height: 32px;height: 32px;border-bottom: 1px solid #eee;padding: 0 6px;
}.option:last-child {border-bottom: none;padding-bottom: 0;
}</style>

总结:

在实际项目中,你可以根据需求进一步完善组件功能,如添加自定义子组件、自定义样式等。掌握组件封装技巧,将有助于提高你的uniapp开发效率。

 

 

 

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

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

相关文章

如何利用免费音频剪辑软件制作出精彩音频

现在有许多免费的音频剪辑软件可供选择&#xff0c;它们为广大用户提供了丰富的功能和便捷的操作体验&#xff0c;让音频编辑变得更加轻松和有趣。接下来&#xff0c;让我们一起走进这些免费音频剪辑软件的世界&#xff0c;探索它们的独特魅力和强大功能。 1.福昕音频剪辑 链…

【Nacos入门到实战十四】Nacos配置管理:集群部署与高可用策略

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

点云补全 学习笔记

目录 Depth completion with convolutions and vision transformers 依赖项&#xff1a; DCNv2 softpoolnet Depth completion with convolutions and vision transformers Zhang, Y., Guo, X., Poggi, M., Zhu, Z., Huang, G., Mattoccia, S.: Completionformer: Depth co…

力扣10.6

134. 加油站 在一条环路上有 n 个加油站&#xff0c;其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车&#xff0c;从第 i 个加油站开往第 i1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发&#xff0c;开始时油箱为空。 给定两个整数数组 …

docker运行arm64架构的镜像、不同平台镜像构建

背景 Docker 允许开发者将应用及其依赖打包成一个轻量级、可移植的容器&#xff0c;实现“一次构建&#xff0c;到处运行”的目标。然而&#xff0c;不同的操作系统和硬件架构对容器镜像有不同的要求。例如&#xff0c;Linux 和 Windows 系统有不同的文件系统和系统调用&#…

【预备理论知识——2】深度学习:线性代数概述

简单地说&#xff0c;机器学习就是做出预测。 线性代数 线性代数是数学的一个分支&#xff0c;主要研究向量空间、线性方程组、矩阵理论、线性变换、特征值和特征向量、内积空间等概念。它是现代数学的基础之一&#xff0c;并且在物理学、工程学、计算机科学、经济学等领域有着…

css3-----2D转换、动画

2D 转换&#xff08;transform&#xff09; 转换&#xff08;transform&#xff09;是CSS3中具有颠覆性的特征之一&#xff0c;可以实现元素的位移、旋转、缩放等效果 移动&#xff1a;translate旋转&#xff1a;rotate缩放&#xff1a;scale 二维坐标系 2D 转换之移动 trans…

OpenGL笔记十九之相机系统

OpenGL笔记十九之相机系统 —— 2024-10-02 晚上 bilibili赵新政老师的教程看后笔记 code review! 文章目录 OpenGL笔记十九之相机系统1.运行1.1.游戏相机1.2.轨迹球相机 2.游戏相机与轨迹球相机切换3.博主笔记本要运行需要更改的文件更改1:28_OpenGL_CameraSystem/applicat…

C语言文件操作(下)(28)

文章目录 前言一、文件的打开和关闭打开打开模式相对路径和绝对路径 关闭 二、文件操作正确流程三、文件顺序读写函数fopenfclosefputcfgetcfputsfgetsfprintffscanfsprintfsscanffwritefread 四、文件随机读写函数fseekftellrewind 五、文件读取结束时候的判断feofferror具体例…

高级 Java Redis 客户端 有哪些?

高级Java Redis客户端主要包括以下几种&#xff1a; 1. Redisson &#xff08;https://github.com/redisson/redisson&#xff09; 特点&#xff1a;Redisson是一个在Redis的基础上实现的Java驻留数据网格&#xff08;In-Memory Data Grid&#xff09;。它不仅是一个Redis的J…

4个顶级的大模型推理引擎

LLM 在文本生成应用中表现出色&#xff0c;例如具有高理解度和流畅度的聊天和代码完成模型。然而&#xff0c;它们的庞大规模也给推理带来了挑战。基本推理速度很慢&#xff0c;因为 LLM 会逐个生成文本标记&#xff0c;需要对每个下一个标记进行重复调用。随着输入序列的增长&…

什么是 Tammann temperature

Tammann temperature (Tt_tt​) 是材料科学中一个重要的概念&#xff0c;它通常用于描述材料的热力学特性和相变行为。其定义与玻璃态和晶态材料的内部原子运动相关。Tammann 温度在研究材料的扩散、再结晶、以及玻璃化转变过程中具有重要意义。 1. Tammann 温度的定义 Tamma…

【AIGC】2022-NIPS-视频扩散模型

2022-NIPS-Video Diffusion Models 视频扩散模型摘要1. 引言2. 背景3. 视频扩散模型3.1. 重建引导采样以改进条件生成 4. 实验4.1. 无条件视频建模4.2. 视频预测4.3. 文本条件视频生成4.3.1 视频与图像建模的联合训练4.3.2 无分类器指导的效果4.3.3 更长序列的自回归视频扩展 5…

06.useEffect

在 React 开发中,正确使用 useEffect 钩子对于优化组件性能至关重要。一个常见但容易被忽视的性能问题是在依赖数组中使用对象作为依赖项。这可能导致不必要的效果重新执行,从而影响应用性能。通过优先使用原始值(如字符串、数字)作为依赖项,我们可以显著提高组件的效率。…

【多线程】详解 CAS 机制

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. CAS 是什么1.1 CAS 具体步骤1.2 CAS 伪代码 2. CAS 的应用2.1 实现原子类2.1.1 AtomInteger 类2.1.2 伪代…

word无法复制粘贴

word无法复制粘贴 使用word时复制粘贴报错 如下&#xff1a; 报错&#xff1a;运行时错误‘53’&#xff0c;文件未找到&#xff1a;MathPage.WLL 这是mathtype导致的。 解决方法 1&#xff09;在mathtype下载目录下找到"\MathType\MathPage\64"下的"mathpa…

Qt开发第一讲

一、Qt项目里面有什么&#xff1f; 对各个文件的解释&#xff1a; Empty.pro文件 QT core gui # 要引入的Qt模块&#xff0c;后面学习到一些内容的时候可能会修改这里 #这个文件相当于Linux里面的makefile文件。makefile其实是一个非常古老的技术了。 #qmake搭配.pr…

C++之模版进阶篇

目录 前言 1.非类型模版参数 2.模版的特化 2.1概念 2.2函数模版特化 2.3 类模板特化 2.3.1 全特化和偏特化 2.3.2类模版特化应用实例 3.模版分离编译 3.1 什么是分离编译 3.2 模板的分离编译 3.3 解决方法 4. 模板总结 结束语 前言 在模版初阶我们学习了函数模版和类…

Redis Stack十部曲之五:管理Redis

文章目录 安全ACLTLS 配置redis.conf配置文件通过命令行传递参数动态修改Redis配置Redis作为缓存使用 Redis SentinelRedis Sentinel像一个分布式系统运行Redis Sentinel配置Redis Sentinelquorum参数其它Sentinel 选项 Redis Sentinel部署模式探索ASCII 图示说明模式1&#xf…

【MySQL】Ubuntu环境下MySQL的安装与卸载

目录 1.MYSQL的安装 2.MySQL的登录 3.MYSQL的卸载 4.设置配置文件 1.MYSQL的安装 首先我们要看看我们环境里面有没有已经安装好的MySQL 我们发现是默认是没有的。 我们还可以通过下面这个命令来确认有没有mysql的安装包 首先我们得知道我们当前的系统版本是什么 lsb_…