完成下拉列表的实现

This commit is contained in:
LittleBoy 2022-12-09 11:11:56 +08:00
parent 8f1153e739
commit f82d972038
3 changed files with 60 additions and 19 deletions

View File

@ -1,15 +1,28 @@
<template>
<li><slot></slot></li>
<li :ref="element" @click="onClick($event)">
<slot></slot>
</li>
</template>
<script lang="ts">
import {defineComponent} from "vue";
import {defineComponent, onMounted, onUpdated, ref} from "vue";
export default defineComponent({
name: "POption",
props:{
value:{
type: [String,Number,Object],
props: {
value: {
type: [String, Number, Object],
}
},
emits: ['select'],
setup(props,context) {
function onClick(e) {
e.target.data = props.value
}
const element = ref<HTMLElement>()
return {
element,onClick
}
}
})

View File

@ -1,13 +1,14 @@
<template>
<div class="select-wrapper" :class="{active:isActive}" v-click-outside="onClose">
<div class="select-box-wrapper" @click="isActive = !isActive">
<div class="select-value">{{ selectValue }}<span class="placeholder">{{ placeholder }}</span></div>
<div class="select-value">{{ selectValue }}<span v-if="!selectValue" class="placeholder">{{ placeholder }}</span>
</div>
<div class="icon-arrow">
<ArrowDown class="icon-select-arrow"/>
</div>
</div>
<div class="select-options-wrapper">
<ul>
<ul @click="onSelect">
<slot></slot>
</ul>
</div>
@ -16,7 +17,7 @@
<script lang="ts">
import ArrowDown from "../icon/ArrowDown.vue";
import {ref} from "vue";
import {defineComponent, nextTick, ref, SetupContext} from "vue";
import {CHANGE_EVENT, UPDATE_MODEL_EVENT} from "../../service/constants";
export interface OptionItemType {
@ -26,7 +27,7 @@ export interface OptionItemType {
// declare var OptionItemArray: OptionItemType[];
export default {
export default defineComponent({
name: "PSelect",
components: {ArrowDown},
props: {
@ -34,6 +35,9 @@ export default {
type: String,
default: '请选择'
},
modelValue: {
type: [String, Number, Object]
}
},
emits: [
UPDATE_MODEL_EVENT,
@ -41,17 +45,35 @@ export default {
'focus',
'blur',
],
setup(props) {
setup(props, ctx: SetupContext) {
const selectValue = ref(props.modelValue)
const isActive = ref(false)
function onClose(){
function onSelect(e: MouseEvent) {
// dom
const target = e.target as HTMLElement;
if (target.tagName.toLowerCase() != 'li') return;
e.preventDefault();
e.stopPropagation();
//
const text = target.textContent
selectValue.value = text
const arr = [].slice.call (target.parentElement.children)
arr.forEach(ele => (ele as HTMLElement).classList.remove("selected"))
target.classList.add("selected")
ctx.emit(UPDATE_MODEL_EVENT,target.data)
onClose()
}
function onClose() {
isActive.value = false
}
return {
selectValue, isActive,onClose
selectValue, isActive, onClose, onSelect
}
}
}
})
</script>
<style lang="less">
@ -62,7 +84,8 @@ export default {
.select-options-wrapper {
display: block;
}
.select-box-wrapper{
.select-box-wrapper {
border-color: var(--primary-color);
box-shadow: 0 0 3px var(--primary-color);
}

View File

@ -20,17 +20,16 @@
</div>
<hr>
商品类型
<p-select>
<p-option value="1">普通商品</p-option>
<p-option class="selected" value="2">精选商品</p-option>
<p-option value="3">秒杀商品</p-option>
<p-select v-model="select">
<p-option v-for="op in options" :key="op.value" :value="op">{{ op.label }}</p-option>
</p-select>
{{ JSON.stringify(select) }}
</div>
</template>
<script lang="ts" setup>
import PInput from "../components/input";
import {reactive} from "vue";
import {reactive, ref} from "vue";
import PSelect from "../components/select/Select.vue";
import POption from "../components/select/Option.vue";
@ -38,6 +37,12 @@ const data = reactive({
a: '1',
b: '2'
})
const options = [
{value: 1, label: '普通商品'},
{value: 2, label: '精选商品'},
{value: 3, label: '秒杀商品'},
]
const select = ref()
</script>
<style scoped>