完成下拉列表的实现

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

View File

@ -1,13 +1,14 @@
<template> <template>
<div class="select-wrapper" :class="{active:isActive}" v-click-outside="onClose"> <div class="select-wrapper" :class="{active:isActive}" v-click-outside="onClose">
<div class="select-box-wrapper" @click="isActive = !isActive"> <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"> <div class="icon-arrow">
<ArrowDown class="icon-select-arrow"/> <ArrowDown class="icon-select-arrow"/>
</div> </div>
</div> </div>
<div class="select-options-wrapper"> <div class="select-options-wrapper">
<ul> <ul @click="onSelect">
<slot></slot> <slot></slot>
</ul> </ul>
</div> </div>
@ -16,7 +17,7 @@
<script lang="ts"> <script lang="ts">
import ArrowDown from "../icon/ArrowDown.vue"; 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"; import {CHANGE_EVENT, UPDATE_MODEL_EVENT} from "../../service/constants";
export interface OptionItemType { export interface OptionItemType {
@ -26,7 +27,7 @@ export interface OptionItemType {
// declare var OptionItemArray: OptionItemType[]; // declare var OptionItemArray: OptionItemType[];
export default { export default defineComponent({
name: "PSelect", name: "PSelect",
components: {ArrowDown}, components: {ArrowDown},
props: { props: {
@ -34,6 +35,9 @@ export default {
type: String, type: String,
default: '请选择' default: '请选择'
}, },
modelValue: {
type: [String, Number, Object]
}
}, },
emits: [ emits: [
UPDATE_MODEL_EVENT, UPDATE_MODEL_EVENT,
@ -41,17 +45,35 @@ export default {
'focus', 'focus',
'blur', 'blur',
], ],
setup(props) { setup(props, ctx: SetupContext) {
const selectValue = ref(props.modelValue) const selectValue = ref(props.modelValue)
const isActive = ref(false) const isActive = ref(false)
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() { function onClose() {
isActive.value = false isActive.value = false
} }
return { return {
selectValue, isActive,onClose selectValue, isActive, onClose, onSelect
}
} }
} }
})
</script> </script>
<style lang="less"> <style lang="less">
@ -62,6 +84,7 @@ export default {
.select-options-wrapper { .select-options-wrapper {
display: block; display: block;
} }
.select-box-wrapper { .select-box-wrapper {
border-color: var(--primary-color); border-color: var(--primary-color);
box-shadow: 0 0 3px var(--primary-color); box-shadow: 0 0 3px var(--primary-color);

View File

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