自己动手丰衣足食系列の自定义下拉框 vue 组件

本文主要是介绍自己动手丰衣足食系列の自定义下拉框 vue 组件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

在页面制作的过程中,经常需要使用到下拉框组件,有时候使用原生的 select 标签十分不便,因为存在 shadow root,shadow root 导致我们有时候修改样式时会非常麻烦

《ShadowRoot介绍》

使用 element UI 下拉框时,又遇到了选择的选项文字内容过长,不能够及时变省略号的现象,需要再次用鼠标点击后才能生效(果然 bug 依旧是程序员不变的主题)

在这里插入图片描述

虽然网上还有其他 UI 组件,但是因为当时我总体使用的是 element UI,不方便改用其他 UI 组件了。

没有条件那就只有自己创造,自己动手丰衣足食。

之前我也写过一篇下拉框组件的博客:自定义一个适应vue的下拉框组件

这一次稍做修改,现在的下拉框组件由两个组件构成

实现的效果:
在这里插入图片描述




正文开始

构思

下拉框组件准备分成两个模块:

  • 第一块是用户能直接看到的内容框,有一个三角形箭头

  • 第二块是用户点击内容框后触发的下拉列表框

在这里插入图片描述

外层

首先,定义一个外部的模块组件 wzc-select.vue

旁边的三角符号为 font-awesome 图形,font-awesome是一个免费的图标字体库

  • 使用npm install font-awesome下载

  • 如果使用 main.js 的话,添加 import ‘font-awesome/css/font-awesome.min.css’;

  • 使用 CDN 的话,用 link 引入:<link href="//netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">

  • 使用时直接在 class 中添加相应的图表名,如<i class="imgthree fa fa-caret-up" ></i>

外部组件调用时,可以对宽高还有 placeholder 进行设置

这里的数据传值由父组件传给子组件数值 props 来完成。

如果想要了解组件之间传值的方式,可以参考此文章:《Vue 组件通信的 8 种方式》

使用 props 接收 width、height、placeholder 三个值,可以使用 default 去设置默认值,如果外部没有传值,就会使用 default 中的数值

props: {placeholder: {type: String,default: '请选择'},width: {type: Number,default: 180},height: {type: Number,default: 40},
}

部分属性使用:root 的方式添加,这里可以自己了解 《:root - CSS》

在 vue 中,可以使用 compute 去设置一个styleVar对象

computed: {styleVar() {return {'--select-height': this.height + 'px','--select-width': this.width + 'px'}}
}

在 div 中通过:style 绑定styleVar

<div class="wzc_select" :style="styleVar" >

这样就可以在下面的 style 中写 CSS 时直接使用这些宽高

.wzc_select {border: 1px solid #E6E6E6;border-radius: 5px;height: var(--select-height);width: var(--select-width);line-height: var(--select-height);
}

外层的分为两部分,下面的 Selectlist 下拉框列表默认是隐藏的。

<template><div class="wzc_select" :style="styleVar" ><!-- 选择框 --><div class="divSelect" :class="{ 'drop_down': isListShow }" ref="divSelect" ><div class="divSelectinput" @click="dropDownSelect"><!-- 选中后的内容 --><div class="selectinfos" :title="label" :class="{ 'no_select': label == '请选择' }"> {{ label }} </div><!-- 三角形图标 isListShow判断三角形图标是否旋转 --><i class="imgthree fa fa-caret-up" :class="{ 'is-reverse': isListShow }"></i></div></div><!-- 下拉框列表 --><transition name="drop-down" ><!-- 下拉框列表isListShow来决定是否收起 --><div class="Selectlist" v-show="isListShow" ref="dropDown"><div class="select_triangle"></div><ul class="wzc_option_list"><slot name="wzc_option"></slot></ul></div></transition></div>
</template>

如果需要在点击弹出下拉框时增加一些动作效果的话,可以使用<transition>框住下拉框。

在 CSS 中写入 transition 动画效果

.drop-down-enter {opacity: 0;transform:translate(0px, -80px) scaleY(0.2);
}
.drop-down-leave-to {opacity: 0;transform:translate(0px, -80px) scaleY(0.2);
}
.drop-down-enter-active {transition: all 0.5s ease-in;
}
.drop-down-leave-active {transition: all 0.5s ease;
}

在点击弹出和收起下拉框时需要做一个 document 的点击判断,如果点击在页面其他部分,就将下拉框收起

document.addEventListener("click", function( e ){if(_this.$refs.divSelect) {if ( !!_this.$refs.divSelect.contains(e.target) || !!_this.$refs.dropDown.contains(e.target) ) return;else_this.isListShow = false;}   
})

这样经过一些的考虑和操作之后,外层的部分就已经写完了

让我们使用importwzc-select.vue导入到页面中去吧,注意要在 components中注册

  • 导入:import wzcSelect from './wzc-select'

  • 注册:components:{ wzcSelect }

  • 调用:<wzc-select class="wzcs" :width="240" :height="40"></wzc-select>

目前当前的效果已经有了,不过比较基础
在这里插入图片描述


内层

内层代码其实相对来说要简单的多,只需要展示外部传入的数据即可

<template><li class="wzc_option" :style="styleVar" @click="currentSelect"><div class="wzc_option_dropdown_item">{{ label }}</div></li>
</template>

在 props 当中接收 CSS 的宽高属性,和 label 内容与 optionid 属性

props: {// 宽width: {type: Number,default: -1,},// 高height: {type: Number,default: 34,},// 内容label: {type: String,},// idoptionid: {type: String,},
},

在点击选择时,使用 $parent 去传递数据给外层 wzc-select.vue 组件

currentSelect() {this.$parent.label = this.label;this.$parent.optionid = this.optionid;this.$parent.isListShow = !this.$parent.isListShow;
}

当然别忘记导入内层组件 import wzcOption from './wzc-option'


外层和内层结合

内层主要是一个<li></li>对象,在外层使用时,可以使用 slot 去让内层存放在相应显示的位置

有关于 slot 插槽的介绍可以参考 ( 当然具体的学习得自己慢慢过一遍 ):

  • https://cn.vuejs.org/v2/api/#slot

  • https://cn.vuejs.org/v2/guide/components-slots.html

在父组件中调用时就可以添加完全了

<wzc-select class="wzcs" :width="240" :height="40"><template v-slot:wzc_option><wzc_optionv-for="item in showlist":key="item.item_id":label="item.item_name":optionid="item.item_id"></wzc_option></template>
</wzc-select>

使用 showlist 为测试数据

showlist: [{item_name: "选项00000000000000000000000000000",item_id: "0",},{item_name: "选项11111111111111111111111111111",item_id: "1",},{item_name: "选项222222222222222222222222222222",item_id: "2",},{item_name: "选项33333333333333333333333333333333",item_id: "3",},
],

好了,现在下拉框的实现效果就达到了需要的样式了

在这里插入图片描述




外层 wzc-select.vue 完整代码

<template><div class="wzc_select" :style="styleVar" ><div class="divSelect" :class="{ 'drop_down': isListShow }" ref="divSelect" ><div class="divSelectinput" @click="dropDownSelect"><!-- 选中后的内容 --><div class="selectinfos" :title="label" :class="{ 'no_select': label == '请选择' }"> {{ label }} </div><!-- 三角形图标 --><i class="imgthree fa fa-caret-up" :class="{ 'is-reverse': isListShow }"></i></div></div><!-- 下拉框列表 --><transition name="drop-down" ><div class="Selectlist" v-show="isListShow" ref="dropDown"><div class="select_triangle"></div><ul class="wzc_option_list"><slot name="wzc_option"></slot></ul></div></transition></div>
</template><script>
export default {name:'wzc_select',components: {},props: {placeholder: {type: String,default: '请选择'},width: {type: Number,default: 180},height: {type: Number,default: 40},},data() {return {label: '',isListShow: false,optionid: ''};},created() {this.label = this.placeholder;},mounted() {let _this = this;document.addEventListener("click", function( e ){if(_this.$refs.divSelect) {if ( !!_this.$refs.divSelect.contains(e.target) || !!_this.$refs.dropDown.contains(e.target) ) return;else_this.isListShow = false;}   })},computed: {styleVar() {return {'--select-height': this.height + 'px','--select-width': this.width + 'px'}}},methods: {dropDownSelect() {this.isListShow = !this.isListShow;},},
};
</script>
<style scoped>.wzc_select {border: 1px solid #E6E6E6;border-radius: 5px;height: var(--select-height);width: var(--select-width);line-height: var(--select-height);}.divSelect {width: 100%;height: 100%;border-radius: 5px;}.drop_down {box-shadow: 0px 0px 6px #709DF7;}.divSelectinput {width: calc(100% - 20px);height: 100%;margin: 0 5px 0 15px;display: flex;}.selectinfos {width: 87.5%;cursor: pointer;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}.no_select {color: #D3DCE6;}.imgthree {width: 12.5%;line-height: var(--select-height);text-align: center;transform: rotate(180deg);transition: all 0.3s;}.imgthree:before {cursor: pointer;color: #D3DCE6;}.imgthree.is-reverse {transform: rotate(0deg);}.Selectlist {margin-top: 10px;z-index: 800;position: relative;background-color: #fff;}.wzc_option_list {border-radius:5px;border:1px solid #E4E7ED;width: 100%; padding: 3px 0px;box-shadow: 0px 0px 6px #709DF7;background-color: #fff;margin: 0;}.select_triangle {width: 14px;height: 7px;position: relative;left: 15px;}.select_triangle::before {position: absolute;content: "";left: 0px;width: 0;height: 0;border-top: 0px solid transparent;border-left: 9px solid transparent;border-right: 9px solid transparent;border-bottom: 8px solid #EBEEF5;}.select_triangle::after {position: absolute;left: 2px;top: 2px;content: "";width: 0;height: 0;border-top: 0px solid transparent;border-left: 7px solid transparent;border-right: 7px solid transparent;border-bottom: 8px solid #fff;  }.drop-down-enter {opacity: 0;transform:translate(0px, -80px) scaleY(0.2);}.drop-down-leave-to {opacity: 0;transform:translate(0px, -80px) scaleY(0.2);}.drop-down-enter-active {transition: all 0.5s ease-in;}.drop-down-leave-active {transition: all 0.5s ease;}
</style>



内层 wzc-option.vue 完整代码

<template><li class="wzc_option" :style="styleVar" @click="currentSelect"><div class="wzc_option_dropdown_item">{{ label }}</div></li>
</template><script>
export default {name: "wzc_select",components: {},props: {width: {type: Number,default: -1,},height: {type: Number,default: 34,},label: {type: String,},optionid: {type: String,},},data() {return {};},created() {},mounted() {},watch: {},computed: {styleVar() {return {"--option-height": this.height + "px","--option-width": this.width == -1? "100%" : this.width + "px",};},},methods: {currentSelect() {this.$parent.label = this.label;this.$parent.optionid = this.optionid;this.$parent.isListShow = !this.$parent.isListShow;// this.$emit('slot-content', {label: this.label, optionid: this.optionid} );}},
};
</script>
<style scoped>
.wzc_option {list-style: none;height: var(--option-height);width: var(--option-width);}
.wzc_option:hover {color: #409eff;font-weight: 700;background-color: #f5f7fa;
}
.wzc_option_dropdown_item {height: 100%;width: calc(100% - 30px);line-height: var(--option-height);cursor: pointer;margin: 0 auto;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;
}</style>

这篇关于自己动手丰衣足食系列の自定义下拉框 vue 组件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/464045

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

【 html+css 绚丽Loading 】000046 三才归元阵

前言:哈喽,大家好,今天给大家分享html+css 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、信息💡1.简介:💡2.外观描述:💡3.使用方式:💡4.战斗方式:💡5.提升:💡6.传说: 📚三、源代码,上代码,可以直接复制使用🎥效果🗂️目录✍️

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能