Skip to content
On this page

tass-ui组件库

Monorepo

概述

一个仓库内包含多个开发项目(模块,包)。这种类型的项目大都在项目根目录下有一个packages文件夹,分多个项目管理。简单来说就是单仓库、多项目。大概结构如下:

-- packages
  -- pkg1
    --package.json
  -- pkg2
    --package.json
--package.json

tass-ui组件库packages下的结构如下:

-- packages
  -- components
    --package.json
  -- constants
    --package.json
  -- eslint-config
    --package.json
  -- theme-chalk
    --package.json
  -- utils
    --package.json
--package.json

ElementUI也是采用这种模式,我们的组件库是参照ElementUI的模式,使用pnpm来开发。

  • 为什么用pnpm?因为它简单高效,它没有太多杂乱的配置,它相比于lerna操作起来方便太多。

实现

为了各个项目之间能够互相引用,我们要新建一个pnpm-workspace.yaml文件将我们的包关联起来。

packages:
    - 'packages/**'
    - 'examples'

优点

  • 存储所有项目代码的单独位置,团队中的每个人都可以访问。
  • 易于重用和共享代码,与团队合作。
  • 很容易理解你的变更对整个项目的影响。
  • 代码重构和代码大变更的最佳选择。
  • 团队成员可以获得整个项目的总体视图。
  • 易于管理依赖关系。

上传Upload

https://juejin.cn/post/7135121438322720799

设计思路

  • 使用<tass-button>组件实现点击上传的按钮,当按钮被点击时,会调用beginUpload()方法,该方法使用input标签的click()方法触发文件选择框。选择完毕后我们可以在原生input的change事件中获取到我们选中的文件。
  • 使用<div class="drop-upload">元素实现拖拽上传功能,当用户将文件拖到这个区域时,会动态改变样式(通过设置isDrag和style),并阻止默认事件。当文件被放置时,会调用handleDrop()方法,该方法将上传的文件添加到文件列表中,并通过emits()方法向父组件发射dropUpload事件。
  • 使用<div class="file">元素来显示已选文件列表,遍历fileList数组,将每个文件的名称和删除按钮显示出来。当删除按钮被点击时,会调用deleteUpload()方法,该方法从文件列表中删除相应的文件,同时通过emits()方法向父组件发射deleteUpload事件。
  • 在submitUpload()方法中,获取到上传的文件对象,将其添加到fileList数组中,同时通过emits()方法向父组件发射changeUpload事件。
  • 使用Vue3中提供的setup()函数来编写组件逻辑,通过defineProps()和defineEmits()定义组件的props和events。在onMounted()生命周期钩子中,使用addEventListener()方法添加事件监听器,实现拖拽上传功能。最后,将组件的状态和方法通过export default导出以供父组件使用。

实现拖拽

实现拖拽上传借助的是drop事件,在组件生命周期onMounted中获取到拖拽区域的DOM,然后监听它的drop事件。

首先给拖拽区域一个ref属性。

vue
<!-- <div class="drop-upload" v-if="props.drop" ref="drag" :style="isDrag?style:''"> -->

然后在组件创建完成后进行事件监听。

vue
onMounted(() => {
    drag.value?.addEventListener('drop', handleDrop)
    drag.value?.addEventListener('dragleave', (e) => {
    isDrag.value=false
    })
    drag.value?.addEventListener('dragenter', (e) => {
    e.preventDefault()
    isDrag.value=true
    })
    drag.value?.addEventListener('dragover', (e) => {
    e.preventDefault()
    isDrag.value=true
    })
})

这里需要阻止dragover的默认事件,不然drop是不生效的。

最后再加两个事件dragenter和dragleave来判断文件是否拖到这个区域从而展示不同样式。

注:HTML5新增了一个api,给一个元素设置 draggable = true 属性时,该元素就会支持拖拽。

progress进度条

设计思路

  • 使用<div class="tas-progress">元素实现线性进度条,在组件中使用props对象接收父组件传来的数据(例如:颜色、百分比等)。根据不同的类型和状态,动态设置进度条的样式和内容。
  • 当进度条类型为“in”时,显示一条粗线条,用另一条细线条表示当前进度百分比。当进度条为100%时,显示文字“满”。
  • 当进度条类型为“out”时,显示圆形进度条。在圆形进度条中,我们使用SVG元素画出了两个环:灰色环代表总进度,实际进度由颜色环表示。通过计算当前进度百分比,动态改变颜色环的stroke-dasharray属性,从而实现动画效果。同时,根据不同的状态,可以在进度条上显示不同的图标或文本。
  • 使用Vue3中提供的setup()函数来编写组件逻辑,通过defineProps()定义组件的props。使用toRefs()将props对象转换为响应式对象,并使用ref()创建一个progressValue变量,该变量表示当前进度对应的值。在watch()函数中监听percent属性的改变,实时更新progressValue的值。最后,将组件状态和方法通过export default导出以供父组件使用。

canvas和svg的区别

  • svg是一种矢量图,而canvas依赖于分辨率,所以svg放大不会失真,但canvas绘制的图形会失真。
  • svg支持事件处理器,而canvas不支持事件处理器。

Todo-List

组件化编码流程

  1. 拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。
  2. 实现动态组件:考虑好数据的存放位置,数据是一个组件在用还是一些组件在用
    • 一个组件在用:放在组件自身即可
    • 一些组件在用:放在他们共同的父组件上(状态提升)
  3. 实现交互:从绑定事件开始

具体实现步骤

  • 该组件主要由三个子组件 MyHeader、MyList 和 MyFooter 组成,它们在父组件 App 中渲染。
  • MyHeader 组件包含了一个 input 元素和一个 button 元素,用于添加新的 todo。在用户输入内容并点击添加按钮时,会触发一个事件(addTodo),向父组件 App 发送一个包含新 todo 内容的对象。
  • MyList 组件根据父组件 App 传递过来的 todos 数组进行渲染,每个 todo 包含一个复选框、一个文本内容和一个删除按钮。当用户勾选或取消勾选复选框时,会触发一个事件(checkTodo),向父组件 App 发送一个 todo id。当用户点击删除按钮时,会触发一个事件(deleteTodo),向父组件 App 发送一个 todo id。
  • MyFooter 组件可以显示当前的 todo 列表状态,包括已完成的数量、未完成的数量和总数。它也包含了两个按钮:全选和清除已完成的 todo。当用户点击全选按钮时,会触发一个事件(checkAllTodo),向父组件 App 发送一个布尔值(true/false)。当用户点击清除已完成的 todo 按钮时,会触发一个事件(clearAllTodo),调用父组件 App 的方法来清除已完成的 todo。
  • 父组件 App 包含了一个名为 todos 的数组,它存储所有的 todo,以及一些方法来处理 todo,如 addTodo、checkTodo、deleteTodo、checkAllTodo 和 clearAllTodo。这些方法通过 props 传递给子组件 MyHeader、MyList 和 MyFooter。
  • 最终,该组件可以实现添加、勾选/取消勾选、删除、全选/取消全选和清除已完成的 todo 等功能的 Todo-List 组件。

MyHeader

  • 该子组件用于显示 Todo 列表的标题和添加新的 todo。在 MyHeader.vue 中,有一个包含输入框的 div 元素,以及一个用于接收用户输入并添加新 todo 的方法(add)。
  • 组件通过绑定 v-model 指令到 title 属性上,来获取用户输入的内容,并在按下回车键时触发 keyup.enter 事件处理函数 add() 将输入转换成一个对象并将其传递给父组件 App。
  • 在 add() 方法中,首先对用户输入进行校验,如果输入为空,则弹出提示框。然后,使用 nanoid 库生成一个唯一的 id,并将用户输入的标题封装成一个 todo 对象。最后,调用父组件 App 中的 addTodo 方法,将新的 todo 对象传递给它,同时清空输入框。
  • 该组件通过使用 props 接收从父组件 App 中传递进来的 addTodo 方法,实现了与父组件的通信。这使得 MyHeader 组件可以将新的 todo 添加到列表中,并更新父组件中的数据。

MyList

  • 该子组件用于显示 Todo 列表并渲染每个 todo 项目。在 MyList.vue 中,有一个包含 ul 元素的模板,列表项则通过使用 v-for 指令从父组件中接收到的 todos 数组进行动态渲染。
  • 该组件通过使用 props 接收来自父组件 App 的数据 todos、方法 checkTodo 和 deleteTodo,赋予子组件 MyItem 能够响应用户交互以更新 todos 数据的能力。
  • MyItem 组件负责渲染单个 todo Item。对于每个 todo,MyList.vue 都提供一个 MyItem 组件实例,并传递给它相应的 todo 数据、checkTodo、deleteTodo 方法。这样,MyItem 组件就可以根据传入的 todo 数据进行渲染,并且在用户与 todo 交互时调用传入的方法来更新数据。
  • 最终,MyList.vue 实现了渲染 todo 列表和将用户操作与父组件中的数据进行同步的功能。

MyItem

  • 该子组件用于渲染单个 todo 项目。在 MyItem.vue 中,有一个包含 li 元素的模板,可以显示一个复选框、todo 内容和一个删除按钮,并且根据传入的 todo 数据进行渲染。
  • 该组件通过使用 props 接收来自父组件 MyList 的数据 todo、方法 checkTodo 和 deleteTodo,赋予组件能够响应用户交互以更新 todos 数据的能力。其中,todo 对象包含了当前 todo 的 id、title 和 done 状态。
  • 当用户勾选或取消勾选复选框时,会触发 @change 事件处理函数 handleCheck(),将当前 todo 的 id 传递给 checkTodo 方法并更新其状态。同时,组件使用 :checked 属性绑定到 todo.done,保持复选框与对应的 todo 状态同步。
  • 当用户点击删除按钮时,会触发 @click 事件处理函数 handleDelete(),弹出确认对话框后,将当前 todo 的 id 传递给 deleteTodo 方法以便从 todos 数组中删除。
  • MyItem.vue 通过使用 props 接收来自父组件 MyList 的数据和方法,并定义了两个事件处理函数来响应用户操作。最终,MyItem.vue 实现了渲染单个 todo 和将用户操作与父组件中的数据进行同步的功能。

MyFooter

  • 该子组件用于显示 Todo 列表的统计信息和操作按钮。在 MyFooter.vue 中,有一个包含 div 元素的模板,其中包括已完成的 todo 数量、总数、全选复选框和清除已完成任务的按钮。
  • 该组件通过使用 props 接收来自父组件 App 的数据 todos、方法 checkAllTodo 和 clearAllTodo,赋予组件能够响应用户交互以更新 todos 数据的能力。
  • MyFooter.vue 使用 computed 属性来计算已完成 todo 的数量,并根据此计算出是否勾选全选复选框的状态。当用户点击全选复选框时,会触发 v-model 指令绑定的 isAll 计算属性的 set 方法,将新状态传递给 checkAllTodo 方法以改变所有的 todo 状态。同样,当用户点击 "清除已完成任务" 按钮时,会触发 clearAllTodo 方法对当前列表中所有已完成的 todo 进行删除。
  • 最终,MyFooter.vue 实现了显示 todo 统计信息、控制全选复选框状态和清除已完成任务等功能。