| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- <template>
- <div class="web-link-input-wrapper">
- <el-input
- v-model="localValue"
- :placeholder="placeholder"
- :disabled="disabled"
- clearable
- :style="inputStyle"
- @change="handleInputChange"
- @keydown="handleKeydown"
- @focus="
- (e: FocusEvent) => {
- if (e.target) (e.target as HTMLInputElement).select();
- }
- "
- >
- <template #append>
- <el-button type="primary" size="small" :disabled="disabled" @click="handleSelectLink"> 选择 </el-button>
- </template>
- </el-input>
- <LinkSelector
- ref="linkSelectorRef"
- v-model:visible="selectorVisible"
- v-model="localValue"
- @confirm="handleLinkConfirm"
- @close="handleSelectorClose"
- />
- </div>
- </template>
- <script setup lang="ts">
- import { ref, watch } from 'vue';
- import LinkSelector from '@/components/LinkSelector/index.vue';
- // 定义属性
- interface Props {
- modelValue?: string;
- placeholder?: string;
- disabled?: boolean;
- inputStyle?: Record<string, any>;
- }
- // 定义事件
- interface Emits {
- (e: 'update:modelValue', value: string): void;
- (e: 'change', value: string): void;
- }
- const props = withDefaults(defineProps<Props>(), {
- modelValue: '',
- placeholder: '请输入链接或点击选择',
- disabled: false,
- inputStyle: () => ({})
- });
- const emit = defineEmits<Emits>();
- // 响应式数据
- const linkSelectorRef = ref();
- const selectorVisible = ref(false);
- const localValue = ref(props.modelValue);
- // 监听props变化
- watch(
- () => props.modelValue,
- (newValue) => {
- if (newValue !== localValue.value) {
- localValue.value = newValue;
- }
- },
- { immediate: true }
- );
- // 监听localValue变化,实现双向绑定
- watch(localValue, (newValue) => {
- if (newValue !== props.modelValue) {
- emit('update:modelValue', newValue);
- }
- });
- // 处理输入框变化
- const handleInputChange = () => {
- emit('change', localValue.value);
- };
- // 打开链接选择器
- const handleSelectLink = () => {
- // 优先使用组件暴露的open方法
- if (linkSelectorRef.value && linkSelectorRef.value.open) {
- linkSelectorRef.value.open();
- } else {
- // 兼容方案
- selectorVisible.value = true;
- }
- };
- // 处理键盘事件
- const handleKeydown = (event: KeyboardEvent) => {
- // 当输入框获取焦点时,按回车键可以打开选择器
- if (event.code === 'Enter' && !props.disabled) {
- handleSelectLink();
- event.preventDefault();
- }
- };
- // 处理链接选择确认
- const handleLinkConfirm = (value: string, linkItem?: any) => {
- localValue.value = value;
- emit('update:modelValue', value);
- emit('change', value);
- selectorVisible.value = false;
- };
- // 处理选择器关闭
- const handleSelectorClose = () => {
- selectorVisible.value = false;
- };
- // 暴露方法给父组件
- defineExpose({
- openSelector: () => {
- handleSelectLink();
- },
- focusInput: () => {
- // 可以在后续实现输入框聚焦功能
- }
- });
- </script>
- <style lang="scss" scoped>
- .web-link-input-wrapper {
- position: relative;
- width: 100%;
- .el-input {
- width: 100%;
- }
- .el-input-group__append {
- padding: 0 15px;
- background-color: transparent;
- border-left: none;
- box-shadow: none;
- }
- .el-button {
- transition: all 0.3s ease;
- &:hover:not(:disabled) {
- transform: translateY(-1px);
- box-shadow: 0 2px 8px rgba(40, 180, 133, 0.3);
- }
- &:active:not(:disabled) {
- transform: translateY(0);
- }
- }
- // 适配不同状态下的样式
- .el-input.is-disabled {
- .el-input-group__append {
- background-color: #f5f7fa;
- }
- }
- // 添加一些间距和布局优化
- display: inline-flex;
- flex-direction: column;
- gap: 4px;
- }
- </style>
|