这是我参与「第五届青训营 」伴学笔记创作活动的第18天
参考资料
列表 List - Ant Design Vue (antdv.com)
基于vue写的, (但是我没有看懂源码(用tsx写的),后面加上不记得插槽,所以卡了很久才大概弄懂)
Descriptions 描述列表 | Element Plus (gitee.io)
Table 表格 | Element Plus (gitee.io)
ps:要实现ant网页上的东西不是单独写一个组件就OK了,它是结合了很多它其他的组件(布局组件,card组件等等)一起实现的。
逻辑:
每个组件都应该有自己的文件夹,包含组件的模板、逻辑和样式文件。
参数传递可以使用Vue的props机制。在组件的props中声明需要接收的参数,然后在组件的模板中使用这些参数。如果需要验证参数的类型或默认值,可以在props中进行声明。
list结构
这里要记住的一点就是前端在写东西都是按照先搭好html架构,再去写其他的css和js,所以一定要想好结构,这个决定了后面能怎么写。
源码结构:list->list-item->list-item-meta(元) 三层嵌套。
后期再看这个结构就发现了它的灵活性。
善用调试工具来看样式和结构,这是最简单直接的方式
ant-vue的源码放了五个插槽,是具名作用域插槽,很重要(插槽的具体使用就是我在这个项目中的收获)
list:
slots: ['extra', 'loadMore', 'renderItem', 'header', 'footer']
list-item:
slot:['actions', 'extra','content']
list-item-meta
slot:['avatar', 'description', 'title']
在这里我把'description'和 'title'放在了一个content里面
问题
一开始就理解错了,不是让你封装一个完整的列表 是对ul li重构 但还是那样的使用模式,自己把东西搞复杂了,真的是搞复杂了,本身没有那么复杂
换成list+list-item+list-item-meta
如果不拆分复用性更差,就无法实现组件库的各种效果,所以一定要多拆分吗,这样才灵活。
为什么要这么去写,因为你想想原生的ul,是不是ul和li,所以应该是两个在一起去是新年,而不是我直接去循环展示出来,要明白逻辑是什么
最重要的
不要担心,要自己创造,因为这个列表完全没有指定是什么样,你完全可以自己想象的去写,不要被限制。
还是那句话,如果觉得很难,一定是没找对录,方法错了,换一条路走。
插槽可以先不写,再后面需要改的时候再往里面放插槽
实现具体步骤
思路不清晰的时候就看这篇文章:
模仿element-ui封装vue组件库(一)_耳鼻喉科魏主任的博客-CSDN博客
里面应该加一个list-item,这个可以是一个vue,直接导入在list组件中,要想一下这个组件放什么,应该具体怎么做,有这个组件主要是灵活性大大提升。
样式的实现是如何通过传入参数来进行改变的,:class=传入参数,根据不同的class来实现不同的样式,就这么简单,例如想要一个large的list,就传:class="large",那么就绑定对应的.list-large样式,在这里面设置font-size="30px",那么久变大了,就这么简单。其他的也是一样,根据传入的样式来决定(设置不同类型的样式,这一步可以抄一下ant-design-vue的样式设置)
样式(scss如何看懂,如何理解)
别忘了在调节样式前进行css初始化: 前端实用:CSS样式初始化 - 简书 (jianshu.com)
scss也是我在本次项目中的收获
scss这样的模式对我现在来说确实太难了,那么我们现在最需要做的就是实现样式
走了弯路,不是一定要像它这样写才可以实现,实现的方法有很多,只要我最后样式实现了就可以
// @import没理解 耽误好久 // 被导入的文件将合并编译到同一个 css文件中 // 被导入的文件中所包含的变量或者混合指令 (mixin) 都可以在导入的文件中使用。
现在最重要的就是样式了,scss和一系列的规范要看懂,可以开始写了。
(这是参考的一个视频好像是,但是忘记在哪看的了)
可以看element plu的样式是如何写的
用变量来代替自己来写,注释里的内容就是这些变量翻译成css的内容
$是变量 @include是使用方法,@mixin是创建方法
Ant Design Vue源码
真的难看懂,tsx没了解过
.tsx是TS使用了jsx语法
渲染函数 & JSX | Vue.js (vuejs.org)
Babel 是一个 JavaScript 编译器。 这些都前端工程化的基础。
组件引入
import { KlList, KlListItem } from 'kunlun-design'
组件在这里被导入 注意引入的是kunlun-design这个打包好的包(单引号),并不是package里的components
所以我们要进行打包后才可以使用,要在全局使用打包命令(pnpm build),之后才可以使用
自己手动添加在kunlun-design是进行打包配置,但是必须要打包出来才可以用
组件源码
list源码:
<template>
<div :class="[n(), size && n(`--${size}`), bordered && n(`--bordered`)]" :style="{ ...style }">
<!-- 第一层 kl-list 绑定的是kl-list kl-list--size kl-list--bordered -->
<!-- 第二层 1.header kl-list--header kl-list-item--bordered -->
<div :class="[header && 'kl-list--header', header && bordered && 'kl-list-item--bordered']">
<slot name="header"></slot>
</div>
<!-- 第二层 2. ui kl-list-items -->
<ul class="kl-list-items">
<template v-for="item in props.dataSource" :key="item">
<!-- 第三层 1. li kl-list-item--bordered -->
<li :class="bordered && 'kl-list-item--bordered'">
<slot name="renderItem" :item="item"></slot>
</li>
</template>
</ul>
<!-- 第二层 3.footer -->
<div
:class="[footer && 'kl-list--footer ', footer && bordered && 'kl-list-item--bordered']"
>
<slot name="footer"></slot>
</div>
<div :class="extra && 'kl-list--extra '">
<slot name="extra"></slot>
</div>
</div>
</template>
<script setup lang="ts">
import { ListProps, sizeValidatorList } from './list'
import { createNamespace } from '@kunlun-design/utils'
import { computed } from 'vue'
import './list.scss'
const props = defineProps(ListProps)
// 这里是props中带有样式设置的时候设置样式的,增加了自主性
const style = computed(() => {
return props.color || props.textColor
? {
'--kl-bg-color': props.color,
'--kl-font-color': props.textColor,
'--kl-border-color': props.color,
'--kl-border': `var(--kl-border-width) var(--kl-border-style) var(--kl-border-color) var(--kl-border-style)`
}
: {}
})
//检测size是否符合规范
const size = computed(() => {
//首先验证的函数不允许是undefined 只允许string类型 如果类型非法就转换到默认类型
if (props.size === undefined) return 'normal'
return sizeValidatorList(props.size) ? props.size : 'normal'
})
defineOptions({
name: 'KlList'
})
const { n } = createNamespace('list')
</script>
<style scoped lang="scss"></style>
list-item源码:
<template>
<div :class="[n()]">
<slot name="content"></slot>
<slot name="extra"></slot>
<slot name="actions"></slot>
</div>
</template>
<script setup lang="ts">
// import { ListProps } from './list';
import './list.scss'
import { createNamespace } from '@kunlun-design/utils'
// const props = defineProps(ListProps)
defineOptions({
name: 'KlListItem'
})
const { n } = createNamespace('list-item')
</script>
<style scoped lang="scss"></style>
list-item-meta源码:
<template>
<div :class="[n()]">
<slot name="avatar"></slot>
<div class="kl-list-item-meta-content">
<div class="kl-list-item-meta-title">
<slot name="title"></slot>
</div>
<div class="kl-list-item-meta-description">
<slot name="description"></slot>
</div>
</div>
</div>
</template>
<script setup lang="ts">
// import { ListProps } from './list';
import './list.scss'
import { createNamespace } from '@kunlun-design/utils'
// const props = defineProps(ListProps)
defineOptions({
name: 'KlListItemMeta'
})
const { n } = createNamespace('list-item-meta')
</script>
<style scoped lang="scss"></style>