【流鶯書籤】基礎組件(Button,Overlay,Dialog,Message)

寫在前面

項目地址

👉👉項目預覽地址,能夠直接設置爲瀏覽器主頁或者桌面快捷方式進行使用javascript

源碼地址

徹底開源,你們能夠隨意研究,二次開發。固然仍是十分歡迎你們點個Star⭐⭐⭐
👉👉源碼連接(gitee)       👉👉源碼連接(github)css

簡介

本文記錄了流鶯書籤封裝的部分基礎組件,包括vue

Buttonjava

Overlaynode

Dialogreact

Messagegit

因爲本項目是爲了練手,因此在某些組件中可能也添加了一些實際並無用到的功能,接下來將逐個介紹這些組件的屬性,方法,以及一些設計思路.github

除了一些特殊的樣式,文章不會大量貼出CSS代碼,因爲我SASS功底不是很好,CSS代碼看起來也是比較臃腫😣😣😣,感興趣的同窗能夠自行查看源碼數組

目錄結構

基本就是一個組件的.vue文件和一個對應的index.ts,index.ts存放一些基礎數據,類型聲明等瀏覽器

├── src 
     ├── assets      // 存放靜態資源
     ├── baseComponents  // 基礎組件
         └──Button    // 按鈕組件
         │    └──Button.vue
         └── Message    // 彈窗組件
              ├──Message.vue
              └──index.ts
                 ......
複製代碼

Button

展現

先來看效果,能夠看到就是鼠標移入移出的時候會有一個動畫

11.gif

屬性

  • title 按鈕的文字
  • backgroundColor 鼠標移入的顏色
  • useAnimation 是否啓用動畫

設計思路/亮點

🌝按鈕的背景顏色使用了vue3新增特性,直接在css中綁定了props的變量backgroundColor,不瞭解新特性的小夥伴能夠前往官網查看喲

🌝經過動態綁定class來啓用動畫,由於css中是給類名animation寫的hover事件,因此若是類名不存在了,動畫天然不生效了

代碼

<template>
  <div class="wh-button-box"> <div class="btn"> <a :class="{animation:useAnimation}" href="#">{{title}}</a> </div> </div>
</template>

<script lang='ts'> import { defineComponent } from 'vue'; export default defineComponent({ name: 'Wh-button', props: { title: { type: String, default: '按鈕', }, backgroundColor: { type: String, default: 'rgba(16, 143, 111, 0.3)', }, useAnimation: { type: Boolean, default: false, }, }, setup() { return {}; }, }); </script>

<style lang='scss'> //此處省略部分CSS代碼,詳情請查看源碼 .wh-button-box { .btn { &:hover .animation::before { transform: skewX(45deg) translateX(200%); } &:hover .animation { background: v-bind('state.color'); } } } </style>
複製代碼

組件中使用

正常傳入屬性使用便可,這裏使用雙標籤純屬我的習慣😁😁

<wh-button @click="onConfirm"  title='確認' :use-animation="true" :background-color="`rgba(160, 21, 114, 0.3)`"></wh-button>
<wh-button @click="onCancle" title='取消' :use-animation="true"></wh-button>
複製代碼

Overlay

展現

先看效果

15.gif

屬性

  • show 是否啓用遮罩層
  • zIndex 遮罩層的z軸座標
  • closeOnClickModal 是否能夠經過點擊遮罩層關閉內容

設計思路/亮點

🌝使用了vue3的新特性teleport,這個組件的做用是把裏面的內容插入到指定的節點當中,我這裏是插入在body裏了

🌝添加了0.3秒的一個過渡效果,這樣顯得平滑一點,這裏須要注意的是vue3中的transition類名發生了一些小變化,我剛開始寫的時候沒注意到,結果過渡效果就沒生效,查了半天才發現v-enter變成了v-enter-form, v-leave變成了v-leave-form,總體的使用方式仍是跟之前同樣,更多具體的變更請移步vue3官網

🌝遮罩層通常都結合其餘組件使用,好比Dialog,因此這裏設置了一個屬性,來配置是否能夠經過點擊遮罩層來關閉Dialog,須要配置closeOnClickModaltrue,並執行父組件的一個close方法

代碼

<template>
  <!-- 傳送門  此處Dom節點會被插在body裏 -->
  <teleport to='body'> <!-- 過渡動畫 添加了0.3s的淡入淡出 顯得更加平滑 --> <transition name="base"> <!-- 遮罩層 --> <div class="overly" :style="`z-index:${zIndex}`" v-if="show" @click='handleClick'></div> </transition> </teleport>
</template>

<script lang='ts'> import { defineComponent } from 'vue'; export default defineComponent({ name: 'Overlay', props: { show: { type: Boolean, default: false, }, zIndex: { type: Number, default: 2000, }, closeOnClickModal: { type: Boolean, default: false, }, }, emits: ['close'], setup(props, { emit }) { const handleClick = () => { if (props.closeOnClickModal) { emit('close'); } return; }; return { handleClick, }; }, }); </script>

<style lang='scss'> //此處省略部分CSS代碼,詳情請查看源碼 //淡入淡出 .base-enter-active, .base-leave-active { transition: all 0.3s ease; } .base-enter-to, .base-leave-from { opacity: 1; } .base-enter-from, .base-leave-to { opacity: 0; } </style>
複製代碼

組件中使用

配置close-on-click-modaltrue並傳入一個close方法,就能夠點擊遮罩層關閉其餘組件了(如Dialog),須要在close方法中手動的設置:show綁定的屬性爲false.

<overlay :show='dialogVisible' @close='onCancle' :close-on-click-modal='true'></overlay>
複製代碼

Dialog

展現

先看效果,點擊的那個黃色圓圈是錄屏軟件自帶的,不是我寫的🤦‍♂️🤦‍♂️🤦‍♂️

12.gif

屬性

  • dialogVisible 是否展現彈窗
  • title 標題
  • width 寬度
  • top 距離頂部的位置

設計思路/亮點

🌝和遮罩層綁定同一個值,能夠在關閉彈窗的同時關閉遮罩層,也能夠給遮罩層傳遞一個close方法,經過點擊遮罩層關閉彈窗

🌝使用teleport將彈窗插入到.Dialog(class='Dialog')中,至於爲何要插入到這裏,只是爲了練習封裝一個用來生成節點的hooks

//建立DOM節點的hook函數 在body中插入一個自定義class的div節點 
//setup函數在執行時等同於created 因此不必寫入生命週期
import { onUnmounted } from 'vue';
const useDOMCreate = (nodeId: string): HTMLDivElement => {
  // 生成一個div的節點
  const node = document.createElement('div');
  // 給賦值一個class
  node.className = nodeId;
  // 在body中插入div節點
  document.body.appendChild(node);
  // 在組件卸載的時候移除dom節點
  onUnmounted(() => {
    document.body.removeChild(node);
  });
  return node;
};
export default useDOMCreate;
複製代碼

🌝使用transition添加了一個淡入淡出的過渡,而且有20px的位移,視覺效果更好

🌝組件自己分爲三個部分,header就是一個標題,body部分是一個插糟,能夠經過父組件添加一些內容進來,

footer部分是兩個button,執行父組件的確認和取消回調.

代碼

<template>
  <!-- 遮罩層 -->
  <overlay :show='dialogVisible' @close='onCancle' :close-on-click-modal='true'></overlay>
  <!-- 傳送門  此處Dom節點會被插在.Dialog裏 -->
  <teleport to='.Dialog'> <div class="dialog-box" v-bind='$attrs'> <!-- 過渡動畫 添加了0.3s的淡入淡出 而且有20px的移動 顯得更加平滑 --> <transition name="dialog"> <div class="dialog-content" v-if='dialogVisible' :style="`width:${width};margin-top:${top}`"> <!-- Dialog組件header部分 --> <div class="dialog-header"> <h5 class="dialog-title">{{title}}</h5> </div> <!-- Dialog組件內容插槽 --> <slot> </slot> <!-- Dialog組件footer部分 --> <div class="dialog-footer"> <wh-button @click="onConfirm" class="footer-btn" title='確認' :use-animation="true" :background-color="`rgba(160, 21, 114, 0.3)`"></wh-button> <wh-button @click="onCancle" class="footer-btn" title='取消' :use-animation="true"></wh-button> </div> </div> </transition> </div> </teleport>
</template>

<script lang='ts'> //此處省略文件引用,詳情請查看源碼 export default defineComponent({ components: { Overlay, WhButton, }, name: 'Dialog', props: { dialogVisible: { type: Boolean, default: false, }, title: { type: String, default: '提示', }, width: { type: String, default: '400px', }, top: { type: String, default: '15vh', }, }, emits: ['cancle', 'confirm'], setup(props, { emit }) { // 建立dom節點 .Dialog useDOMCreate('Dialog'); // 關閉Dialog const onCancle = () => { emit('cancle'); }; const onConfirm = () => { emit('confirm'); }; return { onCancle, onConfirm, }; }, }); </script>

<style lang='scss'> //此處省略部分CSS代碼,詳情請查看源碼 .dialog-enter-active, .dialog-leave-active { transition: all 0.3s ease; } .dialog-enter-to, .dialog-leave-from { opacity: 1; } .dialog-enter-from, .dialog-leave-to { transform: translateY(-20px); opacity: 0; } </style>
複製代碼

組件中使用

正常傳入屬性使用便可,form組件做爲內容插入,有關form組件能夠點擊這裏查看個人另外一篇文章

👉👉流鶯書籤-基礎組件介紹(Form,Input)

<!-- 添加單個書籤的彈窗 -->
<Dialog :dialog-visible='isShowAddMarkDialog' @cancle='onCancle' @confirm='onConfirm' title='添加書籤'> <wh-from ref='form'> </wh-from> </Dialog>
複製代碼

Message

展現

先看效果,這裏只展現了默認的狀況,其實還有其餘顏色的

13.gif

屬性

  • id 標識
  • type 類型
  • message 內容
  • duration 延遲消失的時間
  • offsetNumber 偏移量

設計思路/亮點 🌝使用transition添加了過渡效果,視覺效果拉滿,淡入淡出,而且移動一個身位,經過傳入的類型屬性來綁定class達成不一樣顏色的效果

🌝使用的時候能夠傳入一個配置對象,或者一個字符串,若是是字符串最終仍是會轉換爲對象

🌝使用fixed定位,距離頂部的偏移量經過message的數量來計算,全部的message存放在一個數組中,新增和移除一條message的時候就相應的操做數組,再根據 數組的長度 * 一個固定的高度 ,就能夠算出每一條message的偏移量

🌝給實例添加一個銷燬的方法,在transitionafter-leave週期中觸發這個方法,在這個方法中操做數組刪除數據,並修改props中的offsetNumber來形成視圖的刷新.具體的查看下方代碼以及源碼.

代碼

//Message.vue
<template>
  <!-- 過渡效果 淡入淡出 而且移動一個身位 -->
  <transition name='message' @after-leave="$emit('destroy')"> <div :class="classes" v-show='visiable' :style='styles' class="message"> {{message}} </div> </transition>
</template>

<script lang='ts'> //此處省略文件引用,詳情請查看源碼 export default defineComponent({ name: 'Message', props: { id: { type: String, default: '', }, type: { type: String as PropType<MessageType>, default: 'default', }, message: { type: String, default: '這是一條提示', }, duration: { type: Number, default: 2000, }, offsetNumber: { type: Number, default: 0, }, }, setup(props) { const classes = computed(() => ['message-' + props.type]); const visiable = ref(false); let timer: any = null; const startTimer = () => { timer = setTimeout(() => { visiable.value = false; }, props.duration); }; const styles = computed(() => { return { top: `${(props.offsetNumber - 1) * 55 + 20}px` }; }); // 組件渲染完了顯示 onMounted(() => { visiable.value = true; // 開啓定時器 startTimer(); }); onUnmounted(() => { clearTimeout(timer); }); return { classes, visiable, styles, }; }, }); </script> <style lang='scss'> //此處省略部分CSS代碼,詳情請查看源碼 .message-enter-active, .message-leave-active { transition: all 0.3s ease; } .message-enter-to, .message-leave-from { opacity: 1; } .message-enter-from, .message-leave-to { transform: translate(-50%,-100%); opacity: 0; } </style> 複製代碼
//index.ts
import Message from './Message.vue';
import { createVNode, render, VNode, reactive, computed } from 'vue';
// 類型
export type MessageType = 'success' | 'error' | 'default';
//一條消息的數據
export interface MessageOptions {
  id?: string;
  type?: MessageType;
  message?: string;
  duration?: number;
  offsetNumber?: number;
}

export type MessageParams = MessageOptions | string;
export type MessageList = MessageOptions[];

// 存放全部的message實例 用來計算偏移量
const instances = reactive<VNode[]>([]);
const offsetNumber = computed(() => instances.length + 1);
const createMessage = (options: MessageParams) => {
  // 若是參數是string類型,就把它轉換爲options對象
  if (typeof options === 'string') {
    options = {
      message: options,
    };
  }
  // 把組件建立爲虛擬節點 也就是一個組件實例
  const vnode = createVNode(Message, {
    ...options,
    offsetNumber: offsetNumber.value,
  });

  // 建立一個容器
  const container = document.createElement('div');

  // 把實例渲染到容器裏
  render(vnode, container);
  // 將渲染後的結果 放到body上
  // 由於會多一個div 因此插入第一個孩子
  // 爲何不直接放到body裏,要建立一個容器再取裏面的內容呢 爲了銷燬組件 若是直接放在body裏,就清空全部節點了
  document.body.appendChild(container.firstElementChild!);
  instances.push(vnode);
  // 給實例添加一個銷燬方法
  vnode.props!.onDestroy = () => {
    instances.shift();
    instances.forEach((item: any) => {
      item.component.props.offsetNumber -= 1;
    });
    // 移除dom
    render(null, container);
  };
};

export default createMessage;
複製代碼

組件中使用

函數式調用,傳入配置對象,或者傳入一個字符串便可

//此處省略文件引用
createMessage({ type: 'success', message: '添加標籤成功!' });
複製代碼

寫在最後

請你們不吝賜教,在下方評論或者私信我,十分感謝🙏🙏🙏.

✅認爲我某個部分的設計過於繁瑣,有更加簡單或者更高逼格的封裝方式

✅認爲我部分代碼過於老舊,能夠提供新的API或最新語法

✅對於文章中部份內容不理解

✅解答我文章中一些疑問

✅認爲某些交互,功能須要優化,發現BUG

✅想要添加新功能,對於總體的設計,外觀有更好的建議

最後感謝各位的耐心觀看,既然都到這了,點個 👍贊再走吧

連接整合

🔊項目預覽地址(GitHub Pages):👉👉alanhzw.github.io

🔊項目預覽備用地址(本身的服務器):👉👉warbler.duwanyu.com

🔊源碼地址(gitee):👉👉gitee.com/hzw_0174/Wa…

🔊源碼地址(github):👉👉github.com/alanhzw/War…

🔊項目總體介紹:👉👉juejin.cn/post/696394…

🔊流鶯書籤-從零搭建一個Vite+Vue3+Ts項目:👉👉juejin.cn/post/695130…

🔊流鶯書籤-基礎組件介紹(Form,Input):👉👉juejin.cn/post/696393…

🔊流鶯書籤-基礎組件(Button,Overlay,Dialog,Message):👉👉juejin.cn/post/696394…

🔊流鶯書籤-業務組件介紹:👉👉暫無

🔊個人博客:👉👉www.duwanyu.com

相關文章
相關標籤/搜索