iT邦幫忙

2023 iThome 鐵人賽

DAY 28
0
Software Development

30天!玩轉TypeScript開發書單系統系列 第 28

[Day28] 驅動吧!終於完成自訂標籤文字顏色功能了!超派~~

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20231012/20124462n3NR4qh7Fp.png


引言


在上一篇當中我們只說到了基本的Tags API
現在要更深入實作細節
那就開始吧!


講究的功能


圖片支援
除了標籤外要可以自訂標籤顏色
有鑑於此
我們設計了一顆可愛的新增標籤按鈕
點下它變可以開始CRUD的功能囉
https://ithelp.ithome.com.tw/upload/images/20231012/20124462IhZh1Z55iW.png

https://ithelp.ithome.com.tw/upload/images/20231012/20124462sW2xBzjeDc.png


CRUD


回到好朋友檔案這裡firebase.ts

const tagRef = collection(db, "bookTags");

export interface TagInfoType {
  title: string,
  color:string
}

// 新增一個標籤
export const addTag = (tag: TagInfoType) => {
  console.log(tag);
  return addDoc(tagRef, tag);
};

// 查出所有標籤清單
export const getBookTags = async () => {
 
  const orderedQuery = query(tagRef, orderBy("title"));
  const queryDocs = await getDocs(orderedQuery);
  const results: DocumentData = [];

  if (queryDocs.empty) {
    return results;
  }

  queryDocs.docs.forEach((doc) => {
    const data = doc.data();
    const id = doc.id;
    const folder = { id, ...data };
    results.push(folder);
  });
  return results;
};

// 刪除一個標籤
export const deleteBookTag = async (id: string) => {
  await deleteDoc(doc(db, "bookTags", id));
  return;
};

寫型別


這裡我們先寫好相關的型別
並提供給component做使用

export interface TagInfoType {
  title: string,
  color:string
}

要注意個小技巧是const folder = { id, ...data };
要push到資料裡給Vue的index 使用


標籤切版


我們只要存一個標籤陣列在按鈕送出時同步更新到bookInfo.tags
一樣建立標籤元件AsyncBookTags.vue

...
import { getBookTags, deleteBookTag, addTag, TagInfoType } from "../firebase";


//....
const tagColors = [
  "bg-red-100",
  "bg-pink-100",
  "bg-orange-1",
  "bg-yellow-1",

  "bg-lime-1",
  "bg-[#DAECDA]",
  "bg-[#CDE5EC]",
  "bg-blue-100",
  "bg-lightBlue-1",
  "bg-purple-1",
  "bg-violet-1",
  "bg-[#E7E7E5]",
  "bg-[#EEDFDA]",
];

const handleDelete = (id: string) => {
  const checkResult = confirm("確定刪除嗎?");
  if (checkResult) return deleteBookTag(id);
  return;
};

const newTag = ref(<TagInfoType>{
  title: "",
  color: "",
});

const saveTag = () => {
  if (!newTag.value.title) return alert("請填入標題名稱");
  if (!newTag.value.color) return alert("請選擇顏色");
  addTag(newTag.value);
  tags.value.push(newTag.value)
  sendValueToParent();
  showAddTags.value = !showAddTags.value;
};

const setColor = (color: string) => {
  newTag.value.color = color;
};

template

<template>
  <div>
    <i class="i-iconoir:people-tag">資</i><label class="pr-5">標籤設定</label>

    <div class="pb-2 mt-1 flex justify-start items-center flex-wrap">
      <div
        v-for="tag in tags"
        :key="tag.id"
        :class="[
          'h-8 mb-2 mr-3 px-3 flex items-center justify-between rounded-2 cursor-pointer border-none text-3',
          selectedTags.includes(tag.title)
            ? tag.color
            : ' border-gray-1 border-solid transition',
        ]"
        @click="handleSelectTags(tag.title)"
      >
        {{ tag.title }}

        <button
          type="button"
          class="ml-2 p-1 border-transparent focus:outline-none bg-transparent hover:bg-opacity-30 cursor-pointer"
          @click.stop="handleDelete(tag.id)"
        >
          X
        </button>
      </div>

      <button
        v-if="showAddTags"
        type="button"
        class="h-8 mb-2 mr-3 px-3 border border-none rounded-4 cursor-pointer hover:bg-gray-2"
        bg="gray-100"
        @click="addTagButton"
      >
        <i class="i-mdi:tag-plus-outline">加</i>
       
      </button>

      <button
        v-if="!showAddTags"
        type="button"
        class="h-8 mb-2 mr-3 px-3 border border-none rounded-4 cursor-pointer hover:bg-gray-2"
        bg="gray-100"
        @click="showAddTags = !showAddTags"
      >
        <i class="i-mdi:tag-minus-outline">減</i>
      </button>

      <button
        v-if="!showAddTags"
        type="button"
        class="h-8 mb-2 mr-3 px-3 border border-none rounded-4 cursor-pointer hover:bg-gray-2 text-[#004AAD]"
        bg="gray-100"
        @click="saveTag"
      >
        <i class="i-mdi:tag-check-outline">勾</i>
      </button>

      <div
        v-if="!showAddTags"
        :class="[
          'w-full h-8 mb-2 mr-3 px-3 flex items-center justify-between rounded-2 cursor-pointer border-none border-gray-1 border-solid transition bg-gray-100 hover:border-gray-2 hover:bg-white',
        , newTag.color,
        ]"
        @click="sendValueToParent"
      >
        <input
          v-model="newTag.title"
          class="w-full border-none focus:border-b-2 focus:border-blue-500 rounded-none outline-none bg-transparent"
          type="text"
        />
        <button
          type="button"
          class="ml-2 pr-1 border-transparent focus:outline-none bg-transparent hover:bg-opacity-30 text-gray-3"
        >
          <i class="i-mdi:tag-edit-outline">筆</i>
        </button>
      </div>

      <div
        v-if="!showAddTags"
        class="w-full h-8 mb-2 mr-3 px-3 flex items-center justify-start rounded-2 border-none border-gray-1 border-solid transition bg-gray-1 hover:border-gray-2 hover:bg-white"
      >
        <div
          v-for="color in tagColors"
          :key="color"
          :class="[
            'w-4 h-4 mr-2 rounded-full cursor-pointer border-solid',
            color,
            newTag.color === color ? 'border-gray-3' : 'border-gray-2',
          ]"
          @click="setColor(color)"
        ></div>

        <button
          type="button"
          class="ml-10 pr-1 border-transparent focus:outline-none bg-transparent hover:bg-opacity-30 text-gray-3"
        >
          <i class="i-ic:outline-color-lens">彩</i>
        </button>
      </div>
    </div>
  </div>
</template>

補上圖片
謝謝各位讀者們^_^


上一篇
[Day27] 標籤吧!一文掌握Tags功能:Vue 3 + UnoCSS 設計元件
下一篇
[Day29] 瞬間吧!跟著我一起來:使用GitHub和Netlify輕鬆部署網站
系列文
30天!玩轉TypeScript開發書單系統30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言