feat: convert value select component to composition API

This commit is contained in:
IchliebedichZhu 2024-03-10 10:37:47 +00:00
parent c63ca83894
commit 83f7f5e485
3 changed files with 188 additions and 170 deletions

View File

@ -24,7 +24,7 @@
<script lang="ts" setup>
import { ref } from 'vue'
//
const NAME = 'text-input'
// const NAME = 'text-input'
type TProps = {
label?: string

View File

@ -9,61 +9,65 @@
<div id="text-input-area">
<p v-if="label" class="input-label">{{ label }}</p>
<div :class="{ 'input-wrap': true, active: inputBorder }">
<textarea :maxlength="max" :class="{ 'real-input': true, disable: !editable }" type="text" rows="3" :value="dealValue" :readonly="editable ? false : 'readonly'" @input="updateValue($event.target.value)" @focus="focusInput" @blur="blurInput" />
<textarea
:maxlength="max" :class="{ 'real-input': true, disable: !editable }"
type="text" rows="3" :value="dealValue"
:readonly="!editable" @input="updateValue(($event.target as HTMLTextAreaElement).value)"
@focus="focusInput" @blur="blurInput"
/>
</div>
</div>
</template>
<script>
<script lang="ts" setup>
import { ref, computed } from 'vue'
//
const NAME = 'text-input-area'
// const NAME = 'text-input-area'
export default {
name: NAME,
props: {
label: {
default: '',
},
modelValue: {
default: '',
},
editable: {
default: true,
},
max: {},
},
emits: ['update:modelValue', 'finish'],
data() {
return {
inputBorder: false,
tagText: '',
type TProps = {
label?: string
modelValue?: string
editable?: boolean
max?: string
}
type TEmits = {
(event:'update:modelValue', data: string): void
(event: 'finish', data: string): void
}
const props = withDefaults(defineProps<TProps>(), {
label: '',
modelValue: '',
editable: true,
})
const emit = defineEmits<TEmits>()
const inputBorder = ref(false)
const tagText = ref<string>('')
const dealValue = computed(() => {
return props.modelValue
})
function updateValue(value: string) {
emit('update:modelValue', getValue(value))
}
function focusInput() {
inputBorder.value = true
tagText.value = props.modelValue
}
function blurInput() {
inputBorder.value = false
let v = getValue(props.modelValue)
if (v !== tagText.value) {
emit('finish', v)
}
},
computed: {
dealValue() {
return this.modelValue
// return this.modelValue.replace(/<br\/>/g, '\r\n').replace(/&nbsp;/g, ' ')
},
},
methods: {
updateValue(value) {
this.$emit('update:modelValue', this.getValue(value))
},
focusInput() {
this.inputBorder = true
this.tagText = this.modelValue
},
blurInput() {
this.inputBorder = false
let v = this.getValue(this.modelValue)
if (v !== this.tagText) {
this.$emit('finish', v)
}
},
getValue(value) {
}
function getValue(value: string) {
return value.replace(/\n|\r\n/g, '<br/>').replace(/ /g, '&nbsp;')
},
},
}
</script>

View File

@ -13,18 +13,22 @@
<el-popover placement="bottom-end" trigger="click" width="auto">
<!-- 单列表 -->
<ul v-if="data && Array.isArray(data)" class="list-ul">
<li v-for="listItem in data" :key="typeof listItem === 'object' ? listItem.alias : listItem" :class="{ active: listItem == innerValue }" @click="selectItem(listItem)">
<img v-if="listItem.preview" class="preview" :src="listItem.preview" />
<li
v-for="listItem in data" :key="typeof listItem === 'object' ? listItem.alias : listItem"
:class="{ active: listItem == state.innerValue }"
@click="selectItem(listItem)"
>
<img v-if="listItem.preview" class="preview" :src="listItem.preview" alt="preview" />
<span v-else>{{ (typeof listItem === 'object' ? listItem.alias : listItem) + suffix }}</span>
</li>
</ul>
<!-- tab分类列表 -->
<div v-else class="tabs-wrap">
<el-tabs v-model="activeTab">
<el-tabs v-model="state.activeTab">
<el-tab-pane v-for="(val, key, i) in data" :key="'tab' + i" :label="key" :name="key">
<ul class="list-ul">
<li v-for="listItem in data[key]" :key="typeof listItem === 'object' ? listItem.alias : listItem" :class="{ active: listItem == innerValue }" @click="selectItem(listItem)">
<img v-if="listItem.preview" class="preview" :src="listItem.preview" />
<li v-for="listItem in data[key]" :key="typeof listItem === 'object' ? listItem.alias : listItem" :class="{ active: listItem == state.innerValue }" @click="selectItem(listItem)">
<img v-if="listItem.preview" class="preview" :src="listItem.preview" alt="preview" />
<span v-else :style="{ fontFamily: `'${listItem.value}'` }">{{ (typeof listItem === 'object' ? listItem.alias : listItem) + suffix }}</span>
</li>
</ul>
@ -32,9 +36,16 @@
</el-tabs>
</div>
<template #reference>
<div :class="['input-wrap', { active: inputBorder }]" :style="{ width: inputWidth }">
<div :class="['input-wrap', { active: state.inputBorder }]" :style="{ width: inputWidth }">
<!-- <img v-if="innerPreview" class="preview" :src="innerPreview" /> -->
<input :style="{ fontFamily: modelValue.value }" :class="['real-input', { disable: !disable }]" :readonly="readonly ? 'readonly' : false" type="text" :value="showValue" @input="inputText" @focus="inputBorder = true" @blur="inputBorder = false" @keydown="(e) => opNumber(e)" />
<input
:style="{ fontFamily: modelValue.value }"
:class="['real-input', { disable: !disable }]"
:readonly="readonly" type="text"
:value="showValue"
@input="inputText" @focus="state.inputBorder = true"
@blur="state.inputBorder = false" @keydown="(e) => opNumber(e)"
/>
<!-- <span class="input-unit">{{ suffix }}</span> -->
<div class="op-btn">
<!-- <div class="down" @click="inputBorder = !inputBorder"></div> -->
@ -46,124 +57,127 @@
</div>
</template>
<script>
<script lang="ts" setup>
//
const NAME = 'value-input'
import { ElTabPane, ElTabs } from 'element-plus'
import { computed, onMounted, reactive, ref, watch } from 'vue';
export default {
name: NAME,
components: { ElTabPane, ElTabs },
props: {
label: {
default: '',
},
modelValue: {
default: '',
},
suffix: {
default: '',
},
data: {
required: true,
},
disable: {
default: true,
},
inputWidth: {
default: '80px',
},
// textAlign: {
// default: 'center',
// },
readonly: {
default: false,
},
step: {
default: 1,
},
},
emits: ['finish', 'update:modelValue'],
data() {
return {
type TProps = {
label?: string
modelValue?: Record<string, any>
suffix?: string
data: Record<string, any>
disable?: boolean
inputWidth?: string
readonly?: boolean
step?: number
}
type TEmits = {
(event:'update:modelValue', data: Record<string, any> | string | number): void
(event: 'finish', data: Record<string, any> | string | number): void
}
type TState = {
inputBorder: boolean
tagText: string
width: string | number
innerValue: string
innerPreview: string
activeTab: string
}
const props = withDefaults(defineProps<TProps>(), {
label: '',
modelValue: () => ({}),
suffic: '',
data: () => ({}),
disable: true,
inputWidth: '80px',
readonly: false,
step: 1,
})
const emit = defineEmits<TEmits>()
const state = reactive<TState>({
inputBorder: false,
tagText: '',
width: '0',
innerValue: '',
innerPreview: '',
activeTab: '中文',
})
const selectRef = ref<HTMLElement | null>(null)
const showValue = computed(() => {
return state.innerValue
})
watch(
() => props.modelValue,
() => {
state.innerValue = typeof props.modelValue === 'object' ? props.modelValue.alias : props.modelValue
}
},
computed: {
showValue() {
// return this.innerValue + this.suffix
return this.innerValue
},
},
watch: {
modelValue(value) {
this.innerValue = typeof this.modelValue === 'object' ? this.modelValue.alias : this.modelValue
},
inputBorder(value) {
)
watch(
() => state.inputBorder,
(value) => {
if (value) {
this.tagText = this.innerValue
state.tagText = state.innerValue
} else {
if (this.innerValue !== this.tagText) {
this.$emit('finish', this.innerValue)
if (state.innerValue !== state.tagText) {
emit('finish', state.innerValue)
}
}
},
},
created() {
this.innerValue = typeof this.modelValue === 'object' ? this.modelValue.alias : this.modelValue
},
mounted() {
this.width = this.$refs.select.offsetWidth
// if (Object.prototype.toString.call(this.data) === '[Object Object]') {
// for (const key in this.data) {
// console.log(key)
// break
// }
// }
},
methods: {
selectItem(item) {
}
)
onMounted(() => {
state.innerValue = typeof props.modelValue === 'object' ? props.modelValue.alias : props.modelValue
if (selectRef.value) {
state.width = selectRef.value.offsetWidth
}
})
function selectItem(item: Record<string, any>) {
let value = typeof item === 'object' ? item.alias : item
if (this.innerValue !== value) {
this.innerValue = value
this.innerPreview = item.preview
this.$emit('finish', item)
if (state.innerValue !== value) {
state.innerValue = value
state.innerPreview = item.preview
emit('finish', item)
}
},
inputText(e) {
}
function inputText(e: Event) {
// this.innerValue = e.target.value.replace(RegExp(this.suffix), '')
this.innerValue = e.target.value
state.innerValue = (e.target as HTMLInputElement).value
setTimeout(() => {
this.$emit('finish', this.innerValue)
emit('finish', state.innerValue)
}, 100)
},
opNumber(e) {
}
function opNumber(e: KeyboardEvent) {
e.stopPropagation()
switch (e.keyCode) {
case 38:
typeof this.innerValue === 'number' && this.up()
typeof state.innerValue === 'number' && up()
return
case 40:
typeof this.innerValue === 'number' && this.down()
typeof state.innerValue === 'number' && down()
return
}
},
up() {
this.$emit('update:modelValue', parseInt(this.modelValue || 0, 10) + this.step)
},
down() {
let value = parseInt(this.modelValue || 0, 10) - this.step
}
function up() {
emit('update:modelValue', parseInt(`${props.modelValue}` ?? '0', 10) + props.step)
}
function down() {
let value = parseInt(`${props.modelValue}` ?? '0', 10) - props.step
if (value < 0) {
value = 0
}
this.$emit('update:modelValue', value)
},
},
emit('update:modelValue', value)
}
</script>