Vue3 InlineEdit 示範

在網頁中有一種常見的文字編輯方式,就是點擊文字後點擊的位置變成輸入框,輸入完內容離開後變回純文字,將內容儲存。這個修改方式叫做 InlineEdit ,本篇來示範使用 Vue3 SFC 的方式實作。


InlineEdit.vue
    
<template>
    <input v-if="editMode" type="text" v-model="inputValue" @blur="save" @keyup.enter="save"/>
    <span v-else @click="toggleEdit">{{ value }}</span>
</template>

<script setup lang="ts">
import {ref} from 'vue';

const editMode = ref(false);
const inputValue = ref('');

const props = defineProps({
  value: null as any,
})

/**
 * 切換編輯模式
 */
function toggleEdit() {
  inputValue.value = props.value;
  editMode.value = true;
}

const emits = defineEmits(['update:value']);

/**
 * 離開編輯模式,儲存資料並發送資料修改通知
 */
function save() {
  emits('update:value', inputValue.value); // 發送資料修改通知
  editMode.value = false;
}

</script>
    

    
<template>
    點擊修改:
    <inline-edit v-model:value="value">
    </inline-edit>
</template>


<script setup lang="ts">
import {defineComponent, ref} from 'vue';
import InlineEdit from './components/InlineEdit.vue';

const value = ref('123123');


defineComponent({
  components: {
    'inline-edit': InlineEdit
  },
})

function updateValue(newValue: string) {
  console.log(`App.vue updateValue: value: ${value.value}, ${newValue}`);
  value.value = newValue;
}

</script>
    

使用 v-model 還可以再簡化:
    
<template>
    點擊修改:
    <inline-edit v-model:value="value">
    </inline-edit>
</template>


<script setup lang="ts">
import {defineComponent, ref} from 'vue';
import InlineEdit from './components/InlineEdit.vue';

const value = ref('123123');


defineComponent({
  components: {
    'inline-edit': InlineEdit
  },
});

</script>
    

不過有個小問題,就是沒有內容並離開焦點後就再也回不來了...沒關係我們可以用 CSS 解決:
    
.editable-content {
  display: inline-block; /* 內容為空時也維持矩形 */
  min-width: 50px; /* 限制最小寬度 */
  min-height: 10px; /* 限制最小高度 */
  padding: 2px 5px; /* 增加內距 */
  border: 1px solid transparent; /* 透明邊框 */
  border-radius: 4px; /* 設定圓角 */
  background-color: #f9f9f9; /* 設定背景色 */
  vertical-align: baseline; /* 對齊基線 */
}

.editable-content:hover {
  background-color: #e6e6e6; /* 滑鼠懸停時改變背景色 */
  cursor: pointer; /* 改變滑鼠游標為點擊狀態 */
}
    

那點擊時給予焦點呢?不然要點兩下才可以編輯:
    
// <input v-if="editMode"
       ref="inputRef" 
       type="text" v-model="inputValue" @blur="save" @keyup.enter="save"/>

const inputRef = ref(null);

function toggleEdit() {
  inputValue.value = props.value;
  editMode.value = true;

  nextTick(() => {
    inputRef.value.focus(); // 取得焦點
  });
}
    

更新後的 InlineEdit.vue
    
<template>
  <input v-if="editMode"
         ref="inputRef"
         type="text" v-model="inputValue" @blur="save" @keyup.enter="save"/>
  <span v-else @click="toggleEdit" class="editable-content">{{ value }}</span>
</template>

<script setup lang="ts">
import {nextTick, ref} from 'vue';

const editMode = ref(false);
const inputRef = ref(null);
const inputValue = ref('');

const props = defineProps({
  value: null as any,
})

/**
 * 切換編輯模式
 */
function toggleEdit() {
  inputValue.value = props.value;
  editMode.value = true;

  nextTick(() => {
    inputRef.value.focus(); // 取得焦點
  });
}

const emits = defineEmits(['update:value']);

/**
 * 離開編輯模式,儲存資料並發送資料修改通知
 */
function save() {
  emits('update:value', inputValue.value); // 發送資料修改通知
  editMode.value = false;
}

</script>

<style scoped>
.editable-content {
  display: inline-block; /* 內容為空時也維持矩形 */
  min-width: 50px; /* 限制最小寬度 */
  min-height: 10px; /* 限制最小高度 */
  padding: 2px 5px; /* 增加內距 */
  border: 1px solid transparent; /* 透明邊框 */
  border-radius: 4px; /* 設定圓角 */
  background-color: #f9f9f9; /* 設定背景色 */
  vertical-align: baseline; /* 對齊基線 */
}

.editable-content:hover {
  background-color: #e6e6e6; /* 滑鼠懸停時改變背景色 */
  cursor: pointer; /* 改變滑鼠游標為點擊狀態 */
}
</style>
    



延伸閱讀:
Vue3 component 單檔案元件(SFC)示範(使用元件、傳入參數)
Vue3 component 單檔案元件(SFC) 向上傳遞資料(傳遞參數、觸發事件)

參考資料:
Vue.js - Component v-model

留言