Vue3+ElementPlus下一些场景功能的实现

150 阅读3分钟

在Vue3中,一些属性的调用方法会与Vue2下的有所不同,所以整理了在开发过程中实现过的功能。


el-input组件在鼠标光标位置插入内容

1.封装函数insertAfterCursor,在该函数执行时将指定字符串插入到el-input光标所在的位置。

2.获取元素会用到refs,ref是用来操作某个元素节点的,可以说是document.getElementById的语法糖,在vue2中,可以通过this.来访问到$refs,在vue3中没有this这样获取不到了,但是官网提供了其他方法,在setup()中定义const xxx=ref(null),对应元素上绑定ref="xxx",作为其ref。

3.在vue3中,ref主要有两种用法:

第一种使用方式:操作元素节点:
​
1.在组件上声明
<el-form ref="form"></el-form>
​
2.需要手动声明再使用,Vue3基本取消this的使用,也就是更多的内容为声明式使用
let form = ref();
​
3.然后通过form.value操作其内容
form.value.validate()
​
第二种使用方式:声明响应式数据
<template>
    <div>
        <el-input type="textarea" placeholder="请输入内容" v-model="ContentText" ref="cursorInputRef"></el-input>    //挂载ref,获取文本中的位置属性
        <el-button @click="insertAfterCursor">插入</el-button>
    </div>
</template>
​
<script setup>
import { ref } from 'vue'
const ContentText = ref('')
const cursorInputRef = ref(null)
​
const insertAfterCursor = () => {
    const input = cursorInputRef.value.$refs.textarea;  //由el-input的原本元素决定是input还是textarea
    const start = input.selectionStart;     //光标位置,字符串开头则为0,第二个字符左面则为1,以此类推;如选中段文字则为光标范围起始位置
    const end = input.selectionEnd;     //选中段文字则为光标范围结束位置,否则值与selectionStart相同
    const value = input.value;      //文本域中输入字符串的值
    const word = "123";     //要插入的内容
    ContentText.value = value.slice(0, start) + word + value.slice(end);    //根据光标位置将原字符串分为两个字符串,在两个字符串之间插入目标字符串,最终拼接为插入后的字符串
    input.selectionStart = input.selectionEnd = start + word.length;
}
</script>
​
<style lang="scss">
</style>
​

el-popover实现下拉框与el-scrollbar滚动区域列表实现触底懒加载

1.封装函数listScroll执行判断触底条件并执行触底事件。

<template>
    <el-popover placement="bottom" :width="400" trigger="click">
        <template #reference>
            <div class="input-body">
                <span class="body-placeholder" v-if="listValue == ''">      //没数据时渲染暗文
                    请输入分类名称
                </span>
                <span class="body-content" v-if="listValue != ''">      //有数据时渲染下拉列表选中的值
                    <el-tag type="info" class="body-tag">{{ listValue }}</el-tag>
                </span>
            </div>
        </template>
        <el-scrollbar class="options-area" @scroll="listScroll">
            <div ref="listHeight">      //通过ref获取容器高度
                <div v-for="            item             in             listOptions            " class="option-item"
                    @click="addOption(item, $event)">       //列表项勾选与取消选择事件
                    <el-checkbox class="option-item-checkbox" :model-value="listValue == item.label"></el-checkbox>     //根据条件判断勾选框是否渲染为勾选状态
                    <span :class="listValue == item.label ? 'option-item-text-active' : 'option-item-text'">{{
                        item.label }}</span>
                </div>
            </div>
        </el-scrollbar>
    </el-popover>
</template><script setup>
import { ref } from 'vue'
const listValue = ref('')   //下拉框选中的值
const listHeight = ref(null)    //获取容器高度
const listOptions = ref([{ label: '选项1', value: '001' }, { label: '选项2', value: '002' }, { label: '选项3', value: '003' }, { label: '选项4', value: '004' }, { label: '选项5', value: '005' }, { label: '选项6', value: '006' }, { label: '选项7', value: '007' }, { label: '选项8', value: '008' }, { label: '选项9', value: '009' }, { label: '选项10', value: '010' }])  //第一页默认列表数据
const pageSize = ref(10)    //每页数据数量
const pageNumber = ref(1)   //页码
const listTotal = ref(12)   //数据总数,接口返回赋值
const moreListOptions = ref([{ label: '选项11', value: '011' }, { label: '选项12', value: '012' }])     //懒加载要获取的第二页数据const addOption = (val, e) => {
    if (e.target.tagName !== 'INPUT') return    //冒泡拦截,防止点击事件触发两次
    if (listValue.value == val.label) {     //选中值为已选中值则清空
        listValue.value = ''
    } else {    勾选中赋值
        listValue.value = val.label
    }
}
​
const listScroll = async () => {
    const el = event.target
    const scrollHeight = listHeight.value.scrollHeight
    if (scrollHeight - el.scrollTop - el.clientHeight == 0) {       //判定是否滚动条到底部
        console.log('触底了')
        if (listOptions.value.length < listTotal.value) {       //当前列表数据长度还没到数据总数
            console.log('符合懒加载条件')
            const pageNum = pageNumber.value + 1    //传下一页的页码值
            pageNumber.value = pageNumber.value + 1     //记录的页码值也同步新一页
            getList(pageNum)    //调接口
        }
    }
}
​
const getList = async (pageNum) => {
    try {
        // let req = {
        //     page_no: pageNum ? pageNum : 1,      //查懒加载后新的页码或第一页
        //     page_size: pageSize.value,
        // }
        // let res = await xxApi.xxx(req)
        // if (res.errcode === 0) {
        //     listOptions.value = req.page_no === 1 ? res.data.list : listOptions.value.concat(res.data.list)      如果查的页码为1,则列表直接为返回的列表值;如果不是1的话就是懒加载查新的页,查到的结果拼接现有的列表数据
        //     listTotal.value = res.data.total
        // } else {
        //     ElMessage.error('【' + res.errcode + '】' + res.errmsg)
        // }
        listOptions.value = listOptions.value.concat(moreListOptions.value)
    } catch (err) {
        console.log('查询列表数据错误!', err)
    }
}
​
</script><style lang="scss">
.input-body {
    width: 400px;
    height: 30px;
    border: 1px solid #dcdee2;
    border-radius: 0 3px 3px 0;
    float: left;
    cursor: pointer;
​
    .body-placeholder {
        height: 30px;
        font-size: 12px;
        line-height: 30px;
        margin-left: 10px;
        color: #ccc;
    }
​
    .body-content {
        height: 30px;
        font-size: 12px;
        line-height: 30px;
​
        .body-tag {
            margin-left: 5px;
        }
    }
​
    .body-icon {
        float: right;
        color: #ccc;
        font-size: 16px;
        margin: 6px 10px 0 0;
    }
}
​
.options-area {
    height: 200px !important;
    padding-right: 8px;
​
    .option-item {
        cursor: pointer;
​
        .option-item-checkbox {
            margin-left: 8px;
        }
​
        .option-item-text {
            margin-left: 8px;
            display: inline-block;
            height: 32px;
            line-height: 32px;
            color: #666666;
        }
​
        .option-item-text-active {
            margin-left: 8px;
            display: inline-block;
            height: 32px;
            line-height: 32px;
            color: #197afb;
        }
    }
​
    .option-item:hover {
        background: #e8eaec;
    }
}
</style>