从0到1搭建UI组件库 | 青训营笔记

152 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天

一.Button

disabled属性:

只要父子组件传值并且动态获取这个值并且赋给disabled属性,并且设置一个disabled样式即可。

const props = defineProps({
    type: {
        type: String,
        default: null
    },
    plain: {
        type: Boolean,
        default: false
    },
    round: {
        type: Boolean,
        default: false
    },
    circle: {
        type: Boolean,
        default: false
    },
    disabled: {
        type: Boolean,
        default: false
    }
})

disabled样式:

.one-button.is-disabled{
   cursor: no-drop;
}

补充: cusor:no-drop cursor:not-allowed no-drop:不掉落 指示不能在当前光标位置删除拖动的项。通常表现为一只手或一个有一条线穿过的小圆的指针。
not-allowed:不允许 指示将不执行请求的操作。常被描绘成一个有一条线穿过的圆。 公司自己封装的公共样式中

二.dialog(对话框)

前置知识:

  1. vue过渡动画
  2. sync修饰符
  3. 具名插槽与v-slot指令

参数支持:

参数名参数描述
title对话框标题
width对话框标题
top与顶部的距离
visible是否显示dialog(支持sync修饰符)
参数类型默认值
string提示
string50%
string15vh
booleanfalse

事件支持:

事件名事件描述
opened模态框显示事件
closed模态框关闭事件

插槽说明:

插槽名称插槽描述
defaultdialog的内容
titledialog的标题
footerdialog的底部操作区

dialog组件的基本框架和样式

首先搭建起来dialog组件的框架,暂时不加入插槽,只构建出基本的框架和样式。

框架分为三个部分,头部(header)、内容(body)、底部(footer),基本框架如下:

<template>
 <div class="one-dialog_wrapper">
     <div class="one-dialog">
         <div class="one-dialog_header">
             <slot name="title">
                 <span class="one-dialog_title">{{ title }}</span>
             </slot>
             <button class="one-dialog_headerbtn">
                 <i class="one-icon-close"></i>
             </button>
         </div>
         <div class="one-dialog_body">
             <span>这是一段信息</span>
         </div>
         <div class="one-dialog_footer">
             <my-button>取消</my-button>
             <my-button type="primary">确定</my-button>
         </div>
     </div>
 </div>
</template>
<script setup>
import myButton from './myButton.vue'
import { defineProps } from "vue"
defineProps({
 title: {
     type: String,
     default: '提示'
 }
})
</script>
<style lang="less" scoped>
.one-dialog_wrapper {
 position: fixed;
 top: 0;
 right: 0;
 bottom: 0;
 left: 0;
 overflow: auto;
 margin: 0;
 z-index: 2001;
 background-color: rgba(0, 0, 0, 0.5);

 .one-dialog {
     position: relative;
     margin: 15vh auto 50px;
     background: #fff;
     border-radius: 2px;
     box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
     box-sizing: border-box;
     width: 30%;

     &_header {
         padding: 20px 20px 10px;

         .one-dialog_title {
             line-height: 24px;
             font-size: 18px;
             color: #303133;
         }

         .one-dialog_headerbtn {
             position: absolute;
             top: 20px;
             right: 20px;
             padding: 0;
             background: transparent;
             border: none;
             outline: none;
             cursor: pointer;
             font-size: 16px;

             .one-icon-close {
                 color: 909399
             }
         }
     }

     &_body {
         padding: 30px 20px;
         color: #606266;
         font-size: 14px;
         word-break: break-all;
     }

     &_footer {
         padding: 10px 20px 20px;
         text-align: right;
         box-sizing: border-box;

         ::v-deep .my-button:first-child {
             margin-right: 20px;
         }
     }
 }
}
</style>

补充:在标题放一个具名插槽,如果没有传入则显示默认title.

 <slot name="title">
   <span class="one-dialog_title">{{ title }}</span>
 </slot>

插槽的使用

 <div class="one-dialog_footer" v-if="$slots.footer">
      <slot name="footer"></slot>
  </div>

使用:

    <my-dialog width="20%" top="200px">
      <template v-slot:footer>
        <my-button>取消</my-button>
        <my-button type="primary">确定</my-button>
      </template>
    </my-dialog>

对话框显示与隐藏

利用组件通信即可

//myDialog
const emit = defineEmits(['handleClose'])
const handleClose = () => {
    emit("close", false)
}
//App
 <my-dialog width="20%" top="200px" :visible="visible" @close="close">
      <template v-slot:footer>
        <my-button @click="visible = false">取消</my-button>
        <my-button type="primary" @click="visible = false">确定</my-button>
      </template>
    </my-dialog>

补充: .sync修饰符 (使用饿了么Ui时我们不用定义@close进行取消) 官方解释:我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件两侧都没有明显的变更来源。事实上就是组件不能直接修改 props 外部的数据,强行修改外部数据会引起报错,所以需要在子组件中改变 props 的属性值并更新到父组件中,就会使用到 .sync。本质上 .sync 就是一个语法糖。

v-model 与 .sync 的区别

都是用来实现父子组件之间的数据双向通信,但是 v-model 常用于表单元素,也就是输入类元素,input,单选多选框,select框,多行输入等,.sync 常用于子组件数据改变通过 props 传递更新到父组件中,所以,.sync 不限制标签。