mirror of
https://github.com/palxiao/poster-design.git
synced 2025-07-15 16:02:19 +08:00
feat: convert value select component to composition API
This commit is contained in:
parent
c63ca83894
commit
83f7f5e485
@ -24,7 +24,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
// 文本输入组件
|
||||
const NAME = 'text-input'
|
||||
// const NAME = 'text-input'
|
||||
|
||||
type TProps = {
|
||||
label?: string
|
||||
|
@ -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(/ /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, ' ')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user