sequence
In the process of page creation, we often need to use the drop-down box component, sometimes using the native select tag is inconvenient, because there is a shadow root, shadow root cause we sometimes have to change the style is very troublesome
Introduction to ShadowRoot
When using the Element UI drop down box, I encountered the phenomenon that the selected option text was too long, and the ellipsis could not be changed in time. It took another mouse click to take effect (as expected, bugs were still the theme of programmers).
There were other UI components on the web, but since I was using the Element UI in general at the time, it was hard to switch to other UI components.
There is no condition that only their own creation, their own hands rich food and clothing.
I’ve bloggable about dropdown components before: Customize a VUe-compliant dropdown component
This time with a slight modification, the drop-down box component now consists of two components
The effect of realization:
The text start
conceived
The drop-down box component is ready to be divided into two modules:
-
The first block is a content box that the user can see directly, with a triangular arrow
-
The second block is a drop-down list box triggered when the user clicks on the content box
The outer layer
First, define an external module component, wzc-select.vue
Font awesome is a free icon font library
-
Use NPM install font-awesome to download
-
If using main.js, add import ‘box-awesome/CSS/box-awesome.min.css’;
-
Use the CDN, use the link introduction: < link href = “/ / netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css” rel = “stylesheet >”
-
< I class=”imgthree fa fa-caret-up” >
External components can set width, height, and placeholder values when called
This is done by passing the value of the parent component to the child component, the numerical props.
For more information on how values are passed between components, see this article: 8 Ways Vue Components Communicate.
Props to accept width, height, and placeholder values. Use default to set the default values. If no external values are passed, use default
props: {
placeholder: {
type: String.default: 'Please select'
},
width: {
type: Number.default: 180
},
height: {
type: Number.default: 40}},Copy the code
Some properties are added using the root method. Here you can learn about: root-CSS
In vue, you can use compute to set a styleVar object
computed: {
styleVar() {
return {
'--select-height': this.height + 'px'.'--select-width': this.width + 'px'}}}Copy the code
Bind styleVar to div via :style
<div class="wzc_select" :style="styleVar" >
This allows you to use the width and height directly when writing CSS in the style below
.wzc_select {
border: 1px solid #E6E6E6;
border-radius: 5px;
height: var(--select-height);
width: var(--select-width);
line-height: var(--select-height);
}
Copy the code
The outer one is divided into two parts, and the drop-down list of Selectlist below is hidden by default.
<template>
<div class="wzc_select" :style="styleVar" >
<! -- Select box -->
<div class="divSelect" :class="{ 'drop_down': isListShow }" ref="divSelect" >
<div class="divSelectinput" @click="dropDownSelect">
<! -- Selected content -->
<div class="selectinfos" :title="label" :class="{'no_select': label == 'select'}"> {{ label }} </div>
<! -- triangle icon isListShow -->
<i class="imgthree fa fa-caret-up" :class="{ 'is-reverse': isListShow }"></i>
</div>
</div>
<! -- Drop down list -->
<transition name="drop-down" >
<! -- Drop down list isListShow to determine whether to fold -->
<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>
Copy the code
If you want to add some action to the drop-down box, you can use the
Write the Transition animation into your CSS
.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.5 s ease-in;
}
.drop-down-leave-active {
transition: all 0.5 s ease;
}
Copy the code
You need to make a document click judgment when you click on the popup and when you click on the drop down, and if you click on the other part of the page, it collapses the drop down
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; }})Copy the code
After some thought and manipulation, the outer part is written
Let’s import wzc-select.vue into the page using import, and be sure to register it in Components
-
Import wzcSelect from ‘./wzc-select’
-
Register: Components :{wzcSelect}
-
At present, the current effect has been, but more basic
The inner layer
The inner code is actually much simpler, just displaying the incoming data from the outside
<template>
<li class="wzc_option" :style="styleVar" @click="currentSelect">
<div class="wzc_option_dropdown_item">{{ label }}</div>
</li>
</template>
Copy the code
Receive the CSS width and height attribute in props, as well as the label content and optionID attribute
props: {
/ / wide
width: {
type: Number.default: -1,},/ / high
height: {
type: Number.default: 34,},/ / content
label: {
type: String,},// id
optionid: {
type: String,}},Copy the code
When selecting, use $parent to pass data to the outer wZc-select. vue component
currentSelect() {
this.$parent.label = this.label;
this.$parent.optionid = this.optionid;
this.$parent.isListShow = !this.$parent.isListShow;
}
Copy the code
Import wzcOption from ‘./wzc-option’
The outer layer joins the inner layer
The inner layer is primarily a
object. When used in the outer layer, you can use slots to store the inner layer in the corresponding display location
There are about the introduction of slot slots can refer to (of course, the specific study should be their own slowly over) :
-
Cn.vuejs.org/v2/api/#slo…
-
Cn.vuejs.org/v2/guide/co…
When called in the parent component, you can add complete
<wzc-select class="wzcs" :width="240" :height="40">
<template v-slot:wzc_option>
<wzc_option
v-for="item in showlist"
:key="item.item_id"
:label="item.item_name"
:optionid="item.item_id"
></wzc_option>
</template>
</wzc-select>
Copy the code
Use showlist for the test data
showlist: [
{
item_name: "Option 00000000000000000000000000000".item_id: "0"}, {item_name: "Option 11111111111111111111111111111".item_id: "1"}, {item_name: "Option 222222222222222222222222222222".item_id: "2"}, {item_name: "Option 33333333333333333333333333333333".item_id: "3"],},Copy the code
Ok, now the implementation of the drop-down box has the desired style
Outer WZC -select.vue complete code
<template>
<div class="wzc_select" :style="styleVar" >
<div class="divSelect" :class="{ 'drop_down': isListShow }" ref="divSelect" >
<div class="divSelectinput" @click="dropDownSelect">
<! -- Selected content -->
<div class="selectinfos" :title="label" :class="{'no_select': label == 'select'}"> {{ label }} </div>
<! -- Triangle icon -->
<i class="imgthree fa fa-caret-up" :class="{ 'is-reverse': isListShow }"></i>
</div>
</div>
<! -- Drop down list -->
<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: 'Please select'
},
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.3 s;
}
.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.5 s ease-in;
}
.drop-down-leave-active {
transition: all 0.5 s ease;
}
</style>
Copy the code
Inner wZC-option. vue complete code
<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>
Copy the code