Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【流莺书签】基础组件(Button,Overlay,Dialog,Message)

【流莺书签】基础组件(Button,Overlay,Dialog,Message)

作者头像
一尾流莺
发布于 2022-12-10 02:59:05
发布于 2022-12-10 02:59:05
81100
代码可运行
举报
运行总次数:0
代码可运行

写在前面

项目地址

👉👉项目预览地址,可以直接设置为浏览器主页或者桌面快捷方式进行使用

源码地址

完全开源,大家可以随意研究,二次开发。当然还是十分欢迎大家点个Star⭐⭐⭐

👉👉源码链接(gitee)       👉👉源码链接(github)

简介

本文记录了流莺书签封装的部分基础组件,包括

Button

Overlay

Dialog

Message

由于本项目是为了练手,所以在某些组件中可能也添加了一些实际并没有用到的功能,接下来将逐个介绍这些组件的属性,方法,以及一些设计思路.

除了一些特殊的样式,文章不会大量贴出CSS代码,由于我SASS功底不是很好,CSS代码看起来也是比较臃肿😣😣😣,感兴趣的同学可以自行查看源码

目录结构

基本就是一个组件的.vue文件和一个对应的index.ts,index.ts存放一些基础数据,类型声明等

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
├── src 
     ├── assets      // 存放静态资源
     ├── baseComponents  // 基础组件
         └──Button    // 按钮组件
         │    └──Button.vue
         └── Message    // 弹窗组件
              ├──Message.vue
              └──index.ts
                 ......

Button

展示

先来看效果,可以看到就是鼠标移入移出的时候会有一个动画

属性
  • title 按钮的文字
  • backgroundColor 鼠标移入的颜色
  • useAnimation 是否启用动画设计思路/亮点 🌝按钮的背景颜色使用了vue3新增特性,直接在css中绑定了props的变量backgroundColor,不了解新特性的小伙伴可以前往官网查看哟

🌝通过动态绑定class来启用动画,因为css中是给类名animation写的hover事件,所以如果类名不存在了,动画自然不生效了

代码
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<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 {
    &amp;:hover .animation::before {
      transform: skewX(45deg) translateX(200%);
    }
    &amp;:hover .animation {
      background: v-bind('state.color');
    }
  }
}
</style>
组件中使用

正常传入属性使用即可,这里使用双标签纯属个人习惯😁😁

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<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

展示

先看效果

属性
  • 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方法

代码
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<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.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<overlay :show='dialogVisible' @close='onCancle' :close-on-click-modal='true'></overlay>

Dialog

展示

先看效果,点击的那个黄色圆圈是录屏软件自带的,不是我写的🤦‍♂️🤦‍♂️🤦‍♂️

属性
  • dialogVisible 是否展示弹窗
  • title 标题
  • width 宽度
  • top 距离顶部的位置设计思路/亮点 🌝和遮罩层绑定同一个值,可以在关闭弹窗的同时关闭遮罩层,也可以给遮罩层传递一个close方法,通过点击遮罩层关闭弹窗

🌝使用teleport将弹窗插入到.Dialog(class='Dialog')中,至于为什么要插入到这里,只是为了练习封装一个用来生成节点的hooks

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//创建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,执行父组件的确认和取消回调.

代码
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<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)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!-- 添加单个书签的弹窗 -->
<Dialog :dialog-visible='isShowAddMarkDialog' @cancle='onCancle' @confirm='onConfirm' title='添加书签'>
  <wh-from ref='form'>
    </wh-from>
</Dialog>

Message

展示

先看效果,这里只展示了默认的情况,其实还有其他颜色的

属性
  • id 标识
  • type 类型
  • message 内容
  • duration 延迟消失的时间
  • offsetNumber 偏移量 设计思路/亮点 🌝使用transition添加了过渡效果,视觉效果拉满,淡入淡出,并且移动一个身位,通过传入的类型属性来绑定class达成不同颜色的效果

🌝使用的时候可以传入一个配置对象,或者一个字符串,如果是字符串最终还是会转换为对象

🌝使用fixed定位,距离顶部的偏移量通过message的数量来计算,所有的message存放在一个数组中,新增和移除一条message的时候就相应的操作数组,再根据 数组的长度 * 一个固定的高度 ,就可以算出每一条message的偏移量

🌝给实例添加一个销毁的方法,在transitionafter-leave周期中触发这个方法,在这个方法中操作数组删除数据,并修改props中的offsetNumber来造成视图的刷新.具体的查看下方代码以及源码.

代码
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//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>
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//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;
组件中使用

函数式调用,传入配置对象,或者传入一个字符串即可

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//此处省略文件引用
createMessage({ type: 'success', message: '添加标签成功!' });

写在最后

请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.

✅认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式

✅认为我部分代码过于老旧,可以提供新的API或最新语法

✅对于文章中部分内容不理解

✅解答我文章中一些疑问

✅认为某些交互,功能需要优化,发现BUG

✅想要添加新功能,对于整体的设计,外观有更好的建议

最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧

链接整合

🔊项目预览地址(GitHub Pages):👉👉https://alanhzw.github.io

🔊项目预览备用地址(自己的服务器):👉👉http://warbler.duwanyu.com

🔊源码地址(gitee):👉👉https://gitee.com/hzw_0174/WarblerHomepage

🔊源码地址(github):👉👉https://github.com/alanhzw/WarblerHomepage

🔊项目整体介绍:👉👉https://cloud.tencent.com/developer/article/2190018

🔊流莺书签-从零搭建一个Vite+Vue3+Ts项目:👉👉https://cloud.tencent.com/developer/article/2190014

🔊流莺书签-基础组件介绍(Form,Input):👉👉https://cloud.tencent.com/developer/article/2190015

🔊流莺书签-基础组件(Button,Overlay,Dialog,Message):👉👉https://cloud.tencent.com/developer/article/2190017

🔊流莺书签-业务组件介绍:👉👉暂无

🔊我的博客:👉👉https://www.duwanyu.com

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-05-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【流莺书签】基础组件(Form,Input)
---- 写在前面 项目地址 👉👉项目预览地址,可以直接设置为浏览器主页或者桌面快捷方式进行使用 源码地址 完全开源,大家可以随意研究,二次开发。当然还是十分欢迎大家点个Star⭐⭐⭐ 👉👉源码链接(gitee) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;👉👉源码链接(github) 简介 本文记录了流莺书签封装的部分基础组件,包括 ⭐ Input ⭐ Form 由于本项目是为了练手,所以在某些组件中可能也添加了一些实际并没有用到的功能,接下来将逐个介绍这些组件的属性,方法
一尾流莺
2022/12/10
8910
【流莺书签】基础组件(Form,Input)
【流莺书签】Vue3+TS的收藏网址小项目
“流莺”是我非常喜欢的一个词,本指四处飞翔鸣唱的莺鸟,就像我本身也是一个很随性的人。“流莺书签”是一个用来统一存放、管理收藏网址的网站,虽然浏览器本身自带收藏夹功能,并且还能创建多个文件夹,但我个人觉得查找起来依然很费劲,并且它长的很丑。所以我就想做一个好用又好看的收藏夹,取名“流莺书签”。
一尾流莺
2022/12/10
8890
【流莺书签】Vue3+TS的收藏网址小项目
Vue一些你不知道的东西
解释: teleport组件可以将指定的组件渲染到应用外部的其他位置,就好比,子组件,我在父组件注册之后,通过id指定要渲染到哪个页面上,以下是代码例子:
CRMEB商城源码
2022/06/28
4100
Vue一些你不知道的东西
面试官:用Vue3.0 写过组件吗?如果想实现一个 Modal你会怎么设计?
现在有一个场景,点击新增与编辑都弹框出来进行填写,功能上大同小异,可能只是标题内容或者是显示的主体内容稍微不同
@超人
2021/03/18
1.2K0
面试官:用Vue3.0 写过组件吗?如果想实现一个 Modal你会怎么设计?
Vue3 TypeScript 全局 Message 提示框
实现过一个 vue2 + ts 下的全局的 Message 提示框。闲暇之余想在 vue3 + ts 的框架下也实现此功能。
玖柒的小窝
2021/10/05
2.9K0
Vue3 TypeScript 全局 Message 提示框
Vue 3 + TypeScript 组件封装艺术:从原理到实践
在现代前端开发中,组件化开发已成为主流模式。Vue 3 配合 TypeScript 的组合,为我们提供了更强大的类型系统和更优秀的开发体验。本文将深入探讨如何基于 Vue 3 和 TypeScript 进行高质量的组件封装,并通过实际案例展示最佳实践。
编程小白狼
2025/04/26
2010
Element组件引发的Vue中mixins使用,写出高复用组件
版权声明:本文为原创文章首发于公众号:六小登登 , 你可以随意转载但请务必注明出处!!!关注微信公众号:六小登登,回复 「1024」领取资源大礼包 https://blog.csdn.net/qq_32135281/article/details/87854511
六小登登
2019/02/22
1K0
Element组件引发的Vue中mixins使用,写出高复用组件
vue3.0仿layer.js弹窗|vue3对话框组件
昨天有给大家分享一个vue3.0 mobile端弹框组件v3popup,今天再来分享一个最新开发的vue3.0 pc桌面版弹窗组件v3layer。功能效果有些类似layer.js,支持流畅拖拽、缩放、最大化及全屏等功能。
andy2018
2021/01/04
3.6K0
vue3.0仿layer.js弹窗|vue3对话框组件
Vue3 封装出让后来者难以理解的组件,让你变得不再随时可替代
https://juejin.cn/post/6964954862991704094
coder_koala
2021/07/08
5070
Vue3 封装出让后来者难以理解的组件,让你变得不再随时可替代
vue3使用transition封装弹窗组件
components/popUp <template> <div class="pop"> <transition name="fadeBg"> <div class="pop-bg" v-if="isShow" @click="closePop"></div> </transition> <transition name="fadeUp"> <div class="pop-up" v-if="isS
明知山
2022/05/05
8970
vue3使用transition封装弹窗组件
面试题分享之封装一个弹框组件
题目为: vue3中实现一个父页面的弹窗功能,描述显隐和传参的实现逻辑,(效果截图和关键代码截图)
心安事随
2024/07/29
1220
面试题分享之封装一个弹框组件
vue2基础组件通信案例练习:把案例Todo-list改成使用动画与过度
注意点:让每一个添加和删除的操作有一个柔和的动画效果,有两种方式。方式1:在MyItem添加动画效果使用\<transition>标签;方式2:在MyList中添加效果使用\<transition-group>标签。下面案例代码使用方式2。
刘大猫
2024/10/24
970
Vue动画轻松上手:初学者必学的动画技巧
在当今的Web开发领域,动画已经成为了吸引用户眼球和提升用户体验的关键因素。作为一名前端开发者,你是否想过如何利用Vue.js为你的应用添加炫酷的动画效果?本文将通过案例,带你了解Vue动画的实现方法和技巧。
Front_Yue
2024/08/12
1330
Vue动画轻松上手:初学者必学的动画技巧
Vue3.0 新特性以及使用变更总结(实际工作用到的)
Vue3.0 在去年9月正式发布了,也有许多小伙伴都热情的拥抱Vue3.0。去年年底我们新项目使用Vue3.0来开发,这篇文章就是在使用后的一个总结, 包含Vue3新特性的使用以及一些用法上的变更。
@超人
2021/03/23
2.6K0
Vue3.0 新特性以及使用变更总结(实际工作用到的)
Toast组件开发实践(Vuejs3.x)
Toast组件几乎是没有个组件库必备的组件,通过Toast组件开发可以比较全面的学习Vuejs的相关技能点,一起来看一下~
前端小鑫同学
2023/05/01
1.4K0
vue3全局弹框组件|vue3.0自定义插件实例
目前市面上有些大厂已经推出了Vue3组件库,如:有赞Vant3、饿了么Element-Plus及阿里Ant-design-vue2.0,大家感兴趣的可以去看看。
andy2018
2021/01/01
8K0
vue3全局弹框组件|vue3.0自定义插件实例
VueJS 基础知识
原理:<input type="text" :value="datax" @input="datax = $event.target.value">
老猫-Leo
2023/12/11
2900
VueJS 基础知识
React造轮系列:对话框组件 - Dialog 思路
本轮子是通过 React + TypeScript + Webpack 搭建的,至于环境的搭建这边就不在细说了,自己动手谷歌吧。当然可以参考我的源码。
前端小智@大迁世界
2019/06/15
3.7K0
实用的VUE系列——手把手教你写个vue 插件
声明:本文为稀土掘金技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!
用户7413032
2024/06/25
2170
实用的VUE系列——手把手教你写个vue 插件
自己设计的Vue3的实用项目(内含对项目亮点的实现思路与介绍)
其中,Vue3 是早就学完了的,然后也写了两篇总结或是心得吧,其中有很多都是在做项目中踩出来的坑,所以大家可以看一下,避免之后开发中遇到:
@零一
2021/01/29
1.2K0
自己设计的Vue3的实用项目(内含对项目亮点的实现思路与介绍)
推荐阅读
相关推荐
【流莺书签】基础组件(Form,Input)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档