Vue+Element Plus实现自定义表单弹窗

目录

一、基本框架

1.父组件index.vue

2.子组件FormPop.vue

二、细节补充

1)input、textarea、select、input number

2)daterange、date、monthrange

3)数据定义

4)没改样式的效果

5)最终效果

三、最终代码

1.父组件index.vue

2.子组件FormPop.vue

3.样式文件FormPop.css


一、基本框架

根据目前的Element Plus以及Vue的父子组件传递数据的方式,简单搭个框架。

(虽然是用的Vue3,但由于个人习惯,还是按选项式写法写的)

1.父组件index.vue

首先父组件index.vue:

<template>
    <div class="container">
        <el-button @click="showFormPop">打开表单弹框</el-button>
    </div>
    <FormPop v-if="dialogFormVisible" :formItems="formItems" @closeCallBack="dialogFormVisible = false"
        @submitCallBack="handleConfirm">
    </FormPop>
</template>
  
<script>
import FormPop from "../../components/FormPop/index.vue";

export default {
    name: "index",
    components: {
        FormPop
    },
    data() {
        return {
            dialogFormVisible: false,
        }
    },
    methods: {
        showFormPop() {
            console.log("弹窗显示")
            this.dialogFormVisible = true;
        },
        // 取消对话框弹窗
        handleCancel() {
            this.dialogFormVisible = false;
            console.log("弹窗取消")
        },
        handleConfirm(formData) {
            // 处理弹窗提交
            this.dialogFormVisible = false;
            console.log("弹窗提交成功")
            console.log(formData)
        }
    }
};
</script>
  

代码含义:

父组件屏幕中只有一个按钮,点击按钮触发showFormPop事件,用于改变dialogFormVisible的值,来控制子组件弹窗是否显示

引入子组件FormPop.vue,并向子组件通过 props 传递数据 formItems,用于定义表单里的内容。

closeCallBacksubmitCallBack分别是子组件中点击关闭和点击提交按钮对应的回调函数,在子组件中用emit发送,父组件中监听。

2.子组件FormPop.vue

子组件先搭个框架:

<template>
    <el-dialog title="表单弹窗" v-model="dialogFormVisible" width="70%" :before-close="cancelClick">
        <div class="form-part">
            <el-form :model="formData" ref="form">
                <template v-for="(item, index) in formItems" :key="index">
                    <-- 自定义表单内容 -->
                </template>
                <div class="footer">
                    <el-button type="primary" @click="submitForm">提交</el-button>
                    <el-button @click="resetForm">重置</el-button>
                </div>
            </el-form>
        </div>
    </el-dialog>
</template>
  
<script>

export default {
    name: "Index",
    data() {
        return {
            dialogFormVisible: true,
        };
    },
    created() {
        console.log("created", this.formItems;
    },
    props: {
        formItems: {
            type: Array,
            default: () => []
        }
    },
    methods: {
        cancelClick() {
            this.$emit("closeCallBack", false);
        },

        getFormData() {
            return this.$refs.form.validate();
        },

        submitForm() {
            this.getFormData().then(() => {
                this.$emit("submitCallBack", this.formData);
            }).catch(() => {
                console.log("error");
            });
        },

        resetForm() {
            this.$refs.form.resetFields();
        },
    },
}
</script>
  
<style scoped>
@import '../../styles/FormPop.css';
</style>
  

父子组件中搭好了框架,表单如何显示就看 formItems 中的数据如何定义。

二、细节补充

表单常用的有 input文本输入框、textarea文本域、select下拉选择框、input number数字输入框、日期时间选择器等,以下就是常见样式的子组件内容。

1)input、textarea、select、input number

这几个比较相似所以放在一起。

<el-form-item 
                        v-if="['input', 'textarea', 'select', 'rangeInput'].includes(item.type)"
                        :label="item.label" 
                        :prop="item.prop" 
                        :rules="item.rules" 
                        class="form-item">
                        <div v-if="item.type === 'input' || item.type === 'textarea'">
                            <el-input 
                                v-model="formData[item.prop]"
                                :disabled="item.disabled || false" 
                                :clearable="true"
                                :type="item.type" :placeholder="item.disabled ? item.value : (item.placeholder || '请输入')" />
                            <template v-if="item.inputButtonShow">
                                <el-button plain 
                                    :type="item.inputButtonType" 
                                    @click="handleInputButtonClick(item, index)">
                                    {{ item.inputButtonText }}
                                </el-button>
                            </template>
                        </div>
                        <el-select v-if="item.type === 'select'" 
                            v-model="formData[item.prop]" 
                            :clearable="true"
                            :placecholder="item.placeholder || '请选择'">
                            <el-option v-for="(option) in item.options" 
                                :key="'item-' + option.value || option.id"
                                :label="option.label || option.name" 
                                :value="option.value || option.id" />
                        </el-select>
                        <template v-if="item.type === 'rangeInput'">
                            <div class="range-input">
                                <el-input-number 
                                    :min="item.min || 0" :max="item.max || 100"
                                    v-model="formData[item.prop[0]]" 
                                    :disabled="item.disabled || false">
                                </el-input-number>
                                <span class="dash">~</span>
                                <el-input-number 
                                    :min="item.min || 0" :max="item.max || 100"
                                    v-model="formData[item.prop[1]]" 
                                    :disabled="item.disabled || false">
                                </el-input-number>
                            </div>
                        </template>
                    </el-form-item>

以上代表对一个type为['input', 'textarea', 'select', 'rangeInput']四个中的任意一种的创建el-form-item的方式,通过item.type区分。

label与父组件传递的formItems中的每个itemlabel绑定,propprop绑定等等。

对于input额外增加了紧跟在input输入框后的按钮,(有时候会有input框右侧带个“选择”的按钮的需求,供用户选择,选择后将选中的值更新在input框之类的)用v-if判断item.inputButtonShow的值是否为真,如果为真则右侧显示按钮,为假则只有input框。

2)daterange、date、monthrange

这几个定义比较相近,放在一起。

<el-form-item v-if="['dateRange', 'date', 'monthRange'].includes(item.type)" 
                        :label="item.label"
                        :prop="item.prop" 
                        :rules="item.rules" 
                        class="form-item">
                        <el-date-picker v-if="item.type === 'date'" 
                            v-model="formData[item.prop]" 
                            type="date"
                            :placeholder="item.placeholder || '请选择日期'" 
                            clearable 
                            format="YYYY-MM-DD"
                            value-format="YYYY-MM-DD" 
                            :disabled="item.disabled || false">
                        </el-date-picker>
                        <el-date-picker v-if="item.type === 'dateRange'" 
                            v-model="formData[item.prop]" type="daterange"
                            unlink-panels 
                            clearable 
                            range-separator="-" 
                            start-placeholder="开始日期" 
                            end-placeholder="结束日期"
                            :disabled="item.disabled || false">
                        </el-date-picker>
                        <el-date-picker v-if="item.type === 'monthRange'" 
                            v-model="formData[item.prop]" type="monthrange"
                            unlink-panels 
                            clearable 
                            range-separator="-" 
                            start-placeholder="开始月份" 
                            end-placeholder="结束月份"
                            :disabled="item.disabled || false">
                        </el-date-picker>
                    </el-form-item>

同样的用v-if来区分是哪种类型,其余的自行设置,定义方法和Element Plus基本一样的。

3)数据定义

最后设置一下父组件中的formItems,根据不同的类型需要的键值对来定义:

(在电话号码的验证规则中加了正则表达式的验证)

            formItems: [
                {
                    label: "姓名",
                    prop: "name",
                    type: "input",
                    inputButtonShow: true,
                    inputButtonType: 'primary',
                    inputButtonText: '选择',
                    rules: [
                        { required: true, message: "请输入姓名", trigger: "blur" },
                        { min: 2, max: 10, message: "长度在 2 到 10 个字符", trigger: "blur" }
                    ]
                },
                {
                    label: "电话号码",
                    prop: "phone",
                    type: "input",
                    rules: [
                        { required: true, message: "请输入电话号码", trigger: "blur" },
                        {
                            validator: (rule, value, callback) => {
                                const phonereg = /^1[3-9]\d{9}$|^(\(\d{3,4\)|\d{3,4}-)?\d{7,8}$/;
                                if (phonereg.test(value)) {
                                    callback();
                                } else {
                                    callback(new Error('请输入正确的手机号码'));
                                }
                            }
                        }
                    ]
                },
                {
                    label: "年龄",
                    prop: ["ageMin", "ageMax"],
                    type: "rangeInput",
                    rules: [
                        { required: true, message: "请输入年龄", trigger: "blur" },
                        { type: "number", message: "请输入数字", trigger: "blur" },
                        { min: 1, max: 100, message: "年龄必须在 1 到 100 岁之间", trigger: "blur" }
                    ]
                },
                {
                    label: "地址",
                    prop: "address",
                    type: "input",
                    rules: [
                        { required: true, message: "请输入地址", trigger: "blur" },
                        { min: 5, max: 20, message: "长度在 5 到 20 个字符", trigger: "blur" }
                    ]
                },
                {
                    label: "性别",
                    prop: "gender",
                    type: "select",
                    options: [{ label: "男", value: 1 }, { label: "女", value: 2 }],
                    rules: [
                        { required: true, message: "请选择性别", trigger: "blur" }
                    ]
                },
                {
                    label: "生日",
                    prop: "birthday",
                    type: "date",
                    rules: [
                        { required: true, message: "请选择生日", trigger: "blur" }
                    ],
                },
                {
                    label: "在校时间",
                    prop: "schoolTime",
                    type: "dateRange",

                    rules: [
                        { required: true, message: "请选择生日", trigger: "blur" }
                    ],
                },
                {
                    label: "备注",
                    prop: "remark",
                    type: "textarea",
                }
            ],

4)没改样式的效果

CSS样式都没写,当前的效果如下:

每个item默认的宽度不一致,label长度不一致导致不齐,样式需要改进。

5)最终效果

经过一些修改之后,排版整齐了许多:

当屏幕缩小时,item长度也会随之变小:

当直接点击提交或者所在item未填写数据后失焦时,rules中的验证规则起到作用:

接下来验证数据,表单填写数据如下:

在开发者工具的控制台查看得到的数据,这里的输出的数据是父组件获取到的formData:

三、最终代码

最终代码如下:

1.父组件index.vue

<template>
    <div class="container">
        <el-button @click="showFormPop">打开表单弹框</el-button>
    </div>
    <FormPop v-if="dialogFormVisible" :formItems="formItems" @closeCallBack="dialogFormVisible = false"
        @submitCallBack="handleConfirm">
    </FormPop>
</template>
  
<script>
import FormPop from "../../components/FormPop/index.vue";

export default {
    name: "index",
    components: {
        FormPop
    },
    data() {
        return {
            dialogFormVisible: false,
            formItems: [
                {
                    label: "姓名",
                    prop: "name",
                    type: "input",
                    inputButtonShow: true,
                    inputButtonType: 'primary',
                    inputButtonText: '选择',
                    rules: [
                        { required: true, message: "请输入姓名", trigger: "blur" },
                        { min: 2, max: 10, message: "长度在 2 到 10 个字符", trigger: "blur" }
                    ]
                },
                {
                    label: "电话号码",
                    prop: "phone",
                    type: "input",
                    rules: [
                        { required: true, message: "请输入电话号码", trigger: "blur" },
                        {
                            validator: (rule, value, callback) => {
                                const phonereg = /^1[3-9]\d{9}$|^(\(\d{3,4\)|\d{3,4}-)?\d{7,8}$/;
                                if (phonereg.test(value)) {
                                    callback();
                                } else {
                                    callback(new Error('请输入正确的手机号码'));
                                }
                            }
                        }
                    ]
                },
                {
                    label: "年龄",
                    prop: ["ageMin", "ageMax"],
                    type: "rangeInput"
                },
                {
                    label: "性别",
                    prop: "gender",
                    type: "select",
                    options: [{ label: "男", value: 1 }, { label: "女", value: 2 }],
                    rules: [
                        { required: true, message: "请选择性别", trigger: "blur" }
                    ]
                },
                {
                    label: "生日",
                    prop: "birthday",
                    type: "date",
                    rules: [
                        { required: true, message: "请选择生日", trigger: "blur" }
                    ],
                },
                {
                    label: "在校时间",
                    prop: "schoolTime",
                    type: "dateRange",

                    rules: [
                        { required: true, message: "请选择生日", trigger: "blur" }
                    ],
                },
                {
                    label: "备注",
                    prop: "remark",
                    type: "textarea",
                }
            ],
            formData: {
                name: "",
            }
        }
    },
    created() {
    },
    methods: {
        showFormPop() {
            console.log("弹窗显示")
            this.dialogFormVisible = true;
            console.log(this.dialogFormVisible)
        },
        handleCancel() {
            // 取消对话框弹窗
            this.dialogFormVisible = false;
            console.log("弹窗取消")
        },
        handleConfirm(formData) {
            // 处理弹窗提交
            this.dialogFormVisible = false;
            console.log("弹窗提交成功")
            console.log(formData)
        }
    }
};
</script>

<style scoped>
.container {
    display: flex;
    justify-content: center;
    align-items: center;
    margin-top: 20px;
}
</style>
  

2.子组件FormPop.vue

<template>
    <el-dialog title="表单弹窗" v-model="dialogFormVisible" width="70%" :before-close="cancelClick">
        <div class="form-part">
            <el-form :model="formData" ref="form" class="form-content">
                <template v-for="(item, index) in formItems" :key="index">
                    <!-- 文本输入框、选择框、范围输入框 -->
                    <el-form-item v-if="['input', 'textarea', 'select', 'rangeInput'].includes(item.type)"
                        :label="item.label" :prop="item.prop" :rules="item.rules" label-width="100px" class="form-item">
                        <div v-if="item.type === 'input' || item.type === 'textarea'" class="input-part">
                            <el-input v-model="formData[item.prop]" :disabled="item.disabled || false" :clearable="true"
                                :type="item.type" :placeholder="item.disabled ? item.value : (item.placeholder || '请输入')" />
                            <template v-if="item.inputButtonShow">
                                <el-button plain :type="item.inputButtonType" @click="handleInputButtonClick(item, index)">
                                    {{ item.inputButtonText }}
                                </el-button>
                            </template>
                        </div>
                        <el-select v-if="item.type === 'select'" v-model="formData[item.prop]" :clearable="true"
                            :placecholder="item.placeholder || '请选择'">
                            <el-option v-for="(option) in item.options" :key="'item-' + option.value || option.id"
                                :label="option.label || option.name" :value="option.value || option.id" />
                        </el-select>
                        <template v-if="item.type === 'rangeInput'">
                            <div class="range-input">
                                <el-input-number :min="item.min || 1" :max="item.max || 100"
                                    v-model="formData[item.prop[0]]" style="width: 100%" :disabled="item.disabled || false"
                                    @change="handleRangeInputChange(item.prop[0], $event)">
                                </el-input-number>
                                <span class="dash">~</span>
                                <el-input-number :min="item.min || 1" :max="item.max || 100"
                                    v-model="formData[item.prop[1]]" style="width: 100%" :disabled="item.disabled || false"
                                    @change="handleRangeInputChange(item.prop[1], $event)">
                                </el-input-number>
                            </div>
                        </template>
                    </el-form-item>
                    <!-- 日期范围选择器 -->
                    <el-form-item v-if="['dateRange', 'date', 'monthRange'].includes(item.type)" :label="item.label"
                        :prop="item.prop" :rules="item.rules" label-width="100px" class="form-item">
                        <el-date-picker v-if="item.type === 'date'" v-model="formData[item.prop]" type="date"
                            :placeholder="item.placeholder || '请选择日期'" clearable style="width: 100%" format="YYYY-MM-DD"
                            value-format="YYYY-MM-DD" :disabled="item.disabled || false">
                        </el-date-picker>
                        <el-date-picker v-if="item.type === 'dateRange'" v-model="formData[item.prop]" type="daterange"
                            unlink-panels clearable range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
                            :disabled="item.disabled || false">
                        </el-date-picker>
                        <el-date-picker v-if="item.type === 'monthRange'" v-model="formData[item.prop]" type="monthrange"
                            unlink-panels clearable range-separator="-" start-placeholder="开始月份" end-placeholder="结束月份"
                            :disabled="item.disabled || false">
                        </el-date-picker>
                    </el-form-item>
                </template>
                <div class="footer">
                    <el-button type="primary" @click="submitForm">提交</el-button>
                    <el-button @click="resetForm">重置</el-button>
                </div>
            </el-form>
        </div>
    </el-dialog>
</template>
  
<script>

export default {
    name: "Index",
    data() {
        return {
            formData: {},
            formRules: {},
            dialogFormVisible: true,
        };
    },
    created() {
        console.log("created", this.formItems)
        console.log('age', this.formItems[2].prop[0])
    },
    props: {
        formItems: {
            type: Array,
            default: () => []
        }
    },
    mounted() {
        // 初始化formData中与formItems对应的字段值
        this.formItems.forEach((item) => {
            if (item.prop) {
                if (Array.isArray(item.prop)) {
                    // 对于rangeInput类型,prop是数组的情况
                    item.prop.forEach((prop, index) => {
                        this.formData[prop] = index === 0 ? item.min || 0 : item.max || 100;
                    });
                } else {
                    this.formData[item.prop] = '';
                }
            }
        });
    },
    methods: {
        cancelClick() {
            this.$emit("closeCallBack", false);
        },

        getFormData() {
            console.log("getFormData", this.formData)
            return new Promise((resolve, reject) => {
                this.$refs.form.validate((valid, fields) => {
                    if (valid) {
                        resolve();
                    } else {
                        reject(fields);
                    }
                });
            });
        },

        submitForm() {
            this.getFormData().then(() => {
                this.$emit("submitCallBack", this.formData);
            }).catch(() => {
                console.log("error");
            });
        },

        resetForm() {
            this.$refs.form.resetFields();
        },

        handleInputButtonClick(item, index) {
            console.log("handleInputButtonClick", item, index)
        },

        handleRangeInputChange(prop, event) {
            console.log('改变的值:', event, '数据类型:', typeof event);
            this.formData[prop] = event;
        }
    },
}
</script>
  
<style scoped>
@import '../../styles/FormPop.css';
</style>
  

3.样式文件FormPop.css

* {
    margin: 0;
    padding: 0;
}

.form-item {
    width: 90%;
}

.input-part {
    width: 100%;
    display: flex;
}

.range-input {
    width: 100%;
    display: flex;
    flex-grow: 1;
}

.dash {
    margin: 0 5px;
}

.footer {
    display: flex;
    justify-content: center;
    margin-top: 20px;
    gap: 10%;
}

后续还可以在此基础上进一步扩展,比如增加radio、checkbox等选择框,tag标签等,以及可以结合状态管理器对form表单中的数据进行及时存储。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【插入排序】:直接插入排序、二分插入排序、shell排序

【插入排序】&#xff1a;直接插入排序、二分插入排序、shell排序 1. 直接插入排序1.1 详细过程1.2 代码实现 2. 二分插入排序2.1 详细过程2.2 代码实现 3. shell排序3.1 详细过程3.2 代码实现 1. 直接插入排序 1.1 详细过程 1.2 代码实现 public static void swap(int[]arr,…

PHP 生成分享海报

因为用户端有多个平台&#xff0c;如果做分享海报生成&#xff0c;需要三端都来做&#xff0c;工作量比较大。 所以这个艰巨的任务就光荣的交给后端了。经过一定时间的研究和调试&#xff0c;最终圆满完成了任务&#xff0c;生成分享海报图片实现笔记如下。 目录 准备字体文件…

MySQL底层概述—5.InnoDB参数优化

大纲 1.内存相关参数优化 (1)缓冲池内存大小配置 (2)配置多个Buffer Pool实例 (3)Chunk(块)大小配置 (4)InnoDB缓存性能评估 (5)Page管理相关参数 (6)Change Buffer相关参数优化 2.日志相关参数优化 (1)日志缓冲区相关参数配置 (2)日志文件参数优化 3.IO线程相关参数…

05_JavaScript注释与常见输出方式

JavaScript注释与常见输出方式 JavaScript注释 源码中注释是不被引擎所解释的&#xff0c;它的作用是对代码进行解释。lavascript 提供两种注释的写法:一种是单行注释&#xff0c;用//起头:另一种是多行注释&#xff0c;放在/*和*/之间。 //这是单行注释/* 这是 多行 注释 *…

HTML CSS JS基础考试题与答案

一、选择题&#xff08;2分/题&#xff09; 1&#xff0e;下面标签中&#xff0c;用来显示段落的标签是&#xff08; d &#xff09;。 A、<h1> B、<br /> C、<img /> D、<p> 2. 网页中的图片文件位于html文件的下一级文件夹img中&#xff0c;…

【工具】JS解析XML并且转为json对象

【工具】JS解析XML并且转为json对象 <?xml version1.0 encodingGB2312?> <root><head><transcode>hhhhhhh</transcode></head><body><param>ccccccc</param><param>aaaaaaa</param><param>qqqq<…

如何为 ext2/ext3/ext4 文件系统的 /dev/centos/root 增加 800G 空间

如何为 ext2/ext3/ext4 文件系统的 /dev/centos/root 增加 800G 空间 一、引言二、检查当前磁盘和分区状态1. 使用 `df` 命令检查磁盘使用情况2. 使用 `lsblk` 命令查看分区结构3. 使用 `fdisk` 或 `parted` 命令查看详细的分区信息三、扩展逻辑卷(如果使用 LVM)1. 检查 LVM …

Z2400023基于Java+Servlet+jsp+mysql的酒店管理系统的设计与实现 源码 调试 文档

酒店管理系统的设计与实现 1.摘要2.主要功能3. 项目技术栈运行环境 4.系统界面截图5.源码获取 1.摘要 本文介绍了一个基于Java的酒店管理系统&#xff0c;该系统采用Servlet、JSP、JDBC以及c3p0等技术构建&#xff0c;为酒店提供了一个全面的管理平台。该系统不仅适合酒店进行…

从 Llama 1 到 3.1:Llama 模型架构演进详解

从 Llama 1 到 3.1&#xff1a;Llama 模型架构演进详解 原创 编者按&#xff1a;面对 Llama 模型家族的持续更新&#xff0c;您是否想要了解它们之间的关键区别和实际性能表现&#xff1f;本文将探讨 Llama 系列模型的架构演变&#xff0c;梳理了 Llama 模型从 1.0 到 3.1 的…

ubuntu中使用ffmpeg和nginx推http hls视频流

视频流除了rtmp、rtsp&#xff0c;还有一种是http的hls流&#xff0c;使用http协议传输hls格式的视频数据。 nginx支持推送hls视频流&#xff0c;使用的是rtmp模块&#xff0c;即rtmp流推送成功了&#xff0c;hls流也没问题。怎么推送rtmp流&#xff0c;请参考我的文章&#x…

新版布谷直播软件源码开发搭建功能更新明细

即将步入2025年也就是山东布谷科技专注直播系统开发,直播软件源码出售开发搭建等业务第9年,山东布谷科技不断更新直播软件功能&#xff0c;以适应当前新市场环境下的新要求。山东布谷科技始终秉承初心&#xff0c;做一款符合广大客户需求的直播系统软件。支持广大客户提交更多个…

RocketMQ负载均衡机制解析

消费者在消费消息的时候&#xff0c;需要知道从Broker的哪一个消息队列中去获取消息。 ❝ 所以&#xff0c;在消费者端必须要做负载均衡&#xff0c;即Broker端中多个消费队列分配给同一个消费者组中的哪些消费者消费。 在RocketMQ中&#xff0c;在消费者端有一个&#xff1a;R…

架构-微服务-环境搭建

文章目录 前言一、案例准备1. 技术选型2. 模块设计3. 微服务调用 二、创建父工程三、创建基础模块四、创建用户微服务五、创建商品微服务六、创建订单微服务 前言 ‌微服务环境搭建‌ 使用的电商项目中的商品、订单、用户为案例进行讲解。 一、案例准备 1. 技术选型 maven&a…

Microsoft Excel如何插入多行

1.打开要编辑的excel表&#xff0c;在指定位置&#xff0c;鼠标右键点击“插入”一行 2.按住shift键&#xff0c;鼠标的光标箭头会变化成如下图所示 3.一直按住shift键和鼠标左键&#xff0c;往下拖动&#xff0c;直至到插入足够的行

【K8s】专题十五(4):Kubernetes 网络之 Calico 插件安装、切换网络模式、卸载

本文内容均来自个人笔记并重新梳理&#xff0c;如有错误欢迎指正&#xff01; 如果对您有帮助&#xff0c;烦请点赞、关注、转发、订阅专栏&#xff01; 专栏订阅入口 | 精选文章 | Kubernetes | Docker | Linux | 羊毛资源 | 工具推荐 | 往期精彩文章 【Docker】&#xff08;全…

Web 端语音对话 AI 示例:使用 Whisper 和 llama.cpp 构建语音聊天机器人

大语言模型&#xff08;LLM&#xff09;为基于文本的对话提供了强大的能力。那么&#xff0c;能否进一步扩展&#xff0c;将其转化为语音对话的形式呢&#xff1f;本文将展示如何使用 Whisper 语音识别和 llama.cpp 构建一个 Web 端语音聊天机器人。 系统概览 如上图所示&…

Excel把其中一张工作表导出成一个新的文件

excel导出一张工作表 一个Excel表里有多个工作表&#xff0c;怎么才能导出一个工作表&#xff0c;让其生成新的Excel文件呢&#xff1f; 第一步&#xff1a;首先打开Excel表格&#xff0c;然后选择要导出的工作表的名字&#xff0c;比如“Sheet1”&#xff0c;把鼠标放到“She…

Django+Nginx+uwsgi网站Channels+redis+daphne多人在线聊天实现粘贴上传图片

在DjangoNginxuwsgi网站Channelsredisdaphne多人在线的基础上&#xff08;详见DjangoNginxuwsgi网站使用Channelsredisdaphne实现简单的多人在线聊天及消息存储功能-CSDN博客&#xff09;&#xff0c;实现在输入框粘贴或打开本地图片&#xff0c;上传到网站后返回图片路径&…

【Git】Git 命令参考手册

目录 Git 命令参考手册1. 创建仓库1.1 创建一个新的本地仓库1.2 克隆一个仓库1.3 克隆仓库到指定目录 2. 提交更改2.1 显示工作目录中已修改的文件&#xff0c;准备提交2.2 将文件添加到暂存区&#xff0c;准备提交2.3 将所有已修改的文件添加到暂存区&#xff0c;准备提交2.4 …

TDengine在debian安装

参考官网文档&#xff1a; 官网安装文档链接 从列表中下载获得 Deb 安装包&#xff1b; TDengine-server-3.3.4.3-Linux-x64.deb (61 M) 进入到安装包所在目录&#xff0c;执行如下的安装命令&#xff1a; sudo dpkg -i TDengine-server-<version>-Linux-x64.debNOTE 当…