💡 引言:面试官问我上传组件怎么写?我直接掏出这篇博客!
你是不是也曾在面试中被问到“怎么优雅地写上传组件”?别慌!今天咱们就用 WeUI Uploader 教你搞定它!
通过这篇博客,你不仅能写出代码,还能像老司机一样解释“为什么这么写”。
⚠️ 提前剧透:你会看到“BEM西装打领带”、“浮动布局排队买奶茶”、“伪元素隐身人”三大神比喻!
🚀 第一步:看懂WeUI的“高富帅”命名法(BEM)
技术原理
BEM(Block-Element-Modifier)就像给代码穿西装打领带——结构清晰、层次分明!
<!-- 父容器(Block) -->
<div class="weui-uploader">
<!-- 子元素(Element) -->
<div class="weui-uploader__hd">...</div>
<ul class="weui-uploader__files">
<!-- 状态修饰符(Modifier) -->
<li class="weui-uploader__file weui-uploader__file_selected">...</li>
</ul>
</div>
幽默类比
- Block:就像餐厅的“主菜”,是组件的核心(
.weui-uploader)。 - Element:类似“配菜”,是子元素(
__hd、__files)。 - Modifier:像“加辣”指令,表示状态(
_selected)。
代码注释
<!-- Block: 上传组件 -->
<div class="weui-uploader">
<!-- Element: 头部标题 -->
<div class="weui-uploader__hd">图片上传</div>
<!-- Element: 文件列表 -->
<ul class="weui-uploader__files">
<!-- Modifier: 选中状态 -->
<li class="weui-uploader__file weui-uploader__file_selected"></li>
</ul>
</div>
💡 为什么选BEM?:避免类名冲突,让代码像“菜单分类”一样清晰!
🌟 第二步:浮动布局 vs 弹性布局(Flex)的“奶茶店吵架”
技术原理
WeUI Uploader用 浮动布局 实现文件列表排列:
.weui-uploader__file {
float: left; /* 左浮!像排队买奶茶一样排成一列 */
margin-right: 8px; /* 给“奶茶”之间留点距离 */
}
代码对比
| 布局方式 | 优点 | 缺点 |
|---|---|---|
| 浮动布局 | 适合多列排列(如文件列表) | 需要清除浮动,否则“奶茶洒一地”😅 |
| 弹性布局 | 自动换行、响应式强 | 移动端兼容性稍弱 |
代码注释
/* 浮动布局:左浮!自动换行 */
.weui-uploader__file {
float: left;
width: 96px; /* 每杯奶茶的宽度 */
margin-right: 8px; /* 右边留空,避免“贴脸杀” */
}
💡 为什么选浮动?:移动端屏幕小,浮动布局能快速排满一列,自动换行超方便!
🔧 第三步:Stylus变量+伪元素=“CSS魔法”
技术原理
WeUI用 Stylus变量 定义主题色,通过 伪元素 画出表单边框:
$weui-bg-0 = #ededed // 背景色
$weui-fg-3 = rgba(0,0,0,0.1) // 边框色
.weui-cells::before {
content: ""; // 伪元素就像CSS的“隐身人”
height: 1px; // 画一条1px的边框线
background-color: $weui-fg-3;
}
幽默类比
- Stylus变量:像CSS的“快捷键”,改一个值全站换色!
- 伪元素:CSS界的“隐身人”,默默帮你画线、加图标。
代码注释
// 主题色变量(改这里,全站颜色变魔术!✨)
$weui-bg-0 = #ededed
// 伪元素画边框(别怕!它不会占用空间)
.weui-cells::before {
content: ""; // 必须有content才能显示
height: 1px; // 用background-color画线
}
💡 为什么选伪元素?:避免额外HTML标签,用CSS实现“无痕”边框!
📱 移动端黑科技:滚动更丝滑的“魔法咒语”
技术原理
WeUI用 -webkit-overflow-scrolling: touch 优化移动端滚动:
.page {
-webkit-overflow-scrolling: touch; // 移动端滚动更敏感
overflow: scroll; // 桌面端正常滚动
}
幽默类比
-webkit:像安卓和iOS的“通用语言”,让滚动像“奶茶滑入杯中”一样顺滑。touch:告诉手机:“我要用手滑动,别用鼠标!”
代码注释
/* 移动端滚动优化:手指滑动更丝滑! */
.page {
-webkit-overflow-scrolling: touch; // WebKit内核(安卓/iOS)专属
overflow: scroll; // 桌面端正常滚动
}
💡 为什么选这个方案?:移动端没有鼠标,必须用触摸滚动!而
-webkit是安卓/iOS的“通用语言”。
🧩 语义化标签 & 模块化设计
技术原理
WeUI用 .weui-cells 实现表单统一风格:
<!-- 语义化标签:表单容器 -->
<div class="weui-cells">
<!-- 表单项 -->
<div class="weui-cell">
<div class="weui-cell__bd">上传图片</div>
</div>
</div>
幽默类比
.weui-cells:像“表格”一样整齐排列表单项。- 模块化设计:每个组件独立成模块,像“乐高积木”一样自由组合!
代码注释
<!-- 表单容器 -->
<div class="weui-cells">
<!-- 表单项 -->
<div class="weui-cell">
<div class="weui-cell__bd">上传图片</div>
</div>
</div>
💡 为什么选语义化标签?:让代码更易读,搜索引擎也能看懂!
🧩 上传组件的“魔术师袖口”——负边距技巧
技术原理
WeUI通过 负边距(Negative Margin) 消除布局间隙:
.weui-uploader__bd {
margin-bottom: -8px; /* 消除最后一行的底部空隙 */
margin-right: -8px; /* 消除最后一列的右侧空隙 */
}
幽默类比
- 负边距:像魔术师的“袖口”,偷偷把多余的空间“藏起来”。
- 为什么需要?:如果不用,文件列表的最后几项会像“奶茶店排队时有人突然插队”,导致布局错乱。
代码注释
/* 魔术师的袖口:把多余的空间藏起来! */
.weui-uploader__bd {
margin-bottom: -8px; /* 把最后一行的空白“剪掉” */
margin-right: -8px; /* 把最后一列的空白“剪掉” */
}
💡 为什么选负边距?:用CSS的“小聪明”解决布局问题,比加额外标签更优雅!
🧩 图片上传的“视觉魔术”——背景图设计
技术原理
WeUI用 背景图 实现上传文件的“预览效果”:
.weui-uploader__file {
background: url("https://weui.io/images/pic_160.png") no-repeat 50%;
background-size: cover;
}
幽默类比
background-size: cover:像“拉伸照片贴墙”,无论图片宽高比如何,都能填满96x96的“奶茶杯”。no-repeat:防止图片重复,像“奶茶店只卖一杯,不搞拼盘”😅。
代码注释
/* 背景图魔术:让图片自动填满奶茶杯! */
.weui-uploader__file {
background: url("https://weui.io/images/pic_160.png") no-repeat 50%;
background-size: cover; /* 自动拉伸填满 */
}
💡 为什么选背景图?:避免用
<img>标签,减少DOM节点,性能更优!
🧾 总结:3个必知技巧 + 1个常见坑点
✅ 3个必知技巧
- BEM命名:像“菜单分类”一样清晰!
- 浮动布局:适合多列排列,记得清除浮动!
- 负边距技巧:用“魔术师袖口”消除布局间隙!
❌ 1个常见坑点
- 浮动布局忘清除:会导致“奶茶洒一地”(布局错乱)!
/* 清除浮动的“魔法咒语” */ .clearfix::after { content: ""; display: block; clear: both; }
🚀 动手实践!
- 打开
common.styl,把$weui-bg-0改成粉色,看看页面颜色变魔术! - 尝试给
.weui-uploader__file加个边框,变成“彩色奶茶杯”!
🧩 所有源码大公开!复制粘贴即用!
💡 为什么要展示源码?
“纸上得来终觉浅”,真正的学习是动手写代码!以下是你需要的所有源码,直接复制粘贴即可运行:
📄 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- 设置视口,确保在移动设备上正确显示 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WEUI uploader 源码学习</title>
<!-- 引入样式文件 -->
<link rel="stylesheet" href="./common.css">
</head>
<body>
<!-- 页面主容器 -->
<div class="page">
<!-- 页面头部区域 -->
<header class="page__hd">
<!-- 页面标题 -->
<h1 class="page__title">Uploader</h1>
<!-- 页面描述 -->
<p class="page__desc">
上传组件,支持图片上传、文件上传、视频上传等
</p>
</header>
<!-- 页面主体内容区域 -->
<main class="page__bd">
<!-- WEUI表单单元格容器 -->
<div class="weui-cells weui-cells_form">
<!-- 上传器单元格 -->
<div class="weui-cell weui-cell_uploader">
<!-- 单元格主体内容区域 -->
<div class="weui-cell__bd">
<!-- 上传器主容器 -->
<div class="weui-uploader">
<!-- 上传器头部:标题和计数信息 -->
<div class="weui-uploader__hd">
<!-- 上传器标题 -->
<p class="weui-uploader__title">图片上传</p>
<!-- 上传进度信息:已上传数量/总数量 -->
<div class="weui-uploader__info">
<span>0</span> /
<span>9</span>
</div>
</div>
<!-- 上传器主体:文件列表区域 -->
<div class="weui-uploader__bd">
<!-- 文件列表容器 -->
<ul class="weui-uploader__files">
<!-- 文件项:这里展示了9个空的文件占位符 -->
<li class="weui-uploader__file">
</li>
<li class="weui-uploader__file">
</li>
<li class="weui-uploader__file">
</li>
<li class="weui-uploader__file">
</li>
<li class="weui-uploader__file">
</li>
<li class="weui-uploader__file">
</li>
<li class="weui-uploader__file">
</li>
<li class="weui-uploader__file">
</li>
<li class="weui-uploader__file">
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</body>
</html>
📄 common.css
/* 全局重置样式:清除所有元素的默认边距和内边距 */
* {
margin: 0;
padding: 0;
}
/* 页面主容器样式 */
.page {
/* 绝对定位,占满整个视口 */
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
/* 设置背景色为浅灰色 */
background-color: #ededed;
/* 允许内容滚动 */
overflow: scroll;
/* iOS设备滚动优化 */
-webkit-overflow-scrolling: touch;
/* 盒模型设置 */
box-sizing: border-box;
/* 层级设置 */
z-index: 1;
}
/* 页面头部样式 */
.page .page__hd {
/* 头部内边距 */
padding: 40px;
}
/* 页面标题样式 */
.page .page__hd .page__title {
/* 左对齐 */
text-align: left;
/* 字体大小 */
font-size: 20px;
/* 字体粗细 */
font-weight: 400;
}
/* 页面描述样式 */
.page .page__hd .page__desc {
/* 顶部外边距 */
margin-top: 4px;
/* 半透明黑色文字 */
color: rgba(0,0,0,0.55);
/* 左对齐 */
text-align: left;
/* 字体大小 */
font-size: 14px;
}
/* WEUI单元格容器样式 */
.weui-cells {
/* 顶部外边距 */
margin-top: 8px;
/* 白色背景 */
background: #fff;
/* 相对定位,为伪元素定位提供参考 */
position: relative;
/* 隐藏溢出内容 */
overflow: hidden;
}
/* 单元格容器顶部边框线(使用伪元素实现) */
.weui-cells::before {
content: "";
/* 绝对定位 */
position: absolute;
left: 0;
right: 0;
/* 边框线高度 */
height: 1px;
/* 半透明黑色边框 */
background-color: rgba(0,0,0,0.1);
/* 层级设置 */
z-index: 2;
}
/* 单个单元格样式 */
.weui-cell {
/* 内边距 */
padding: 16px;
/* 相对定位 */
position: relative;
/* 弹性布局 */
display: flex;
/* 垂直居中对齐 */
align-items: center;
/* 行高设置 */
line-height: 1.41176471;
}
/* 单元格主体内容区域 */
.weui-cell .weui-cell__bd {
/* 弹性增长,占据剩余空间 */
flex: 1;
}
/* 上传器单元格特殊样式 */
.weui-cell__uploader {
/* 底部增加内边距,为上传器内容留出更多空间 */
padding-bottom: 24px;
}
/* 上传器头部样式 */
.weui-uploader .weui-uploader__hd {
/* 弹性布局 */
display: flex;
/* 底部内边距 */
padding-bottom: 12px;
/* 垂直居中对齐 */
align-items: center;
}
/* 上传器标题样式 */
.weui-uploader .weui-uploader__hd .weui-uploader__title {
/* 弹性增长,占据剩余空间 */
flex: 1;
}
/* 上传器信息(计数)样式 */
.weui-uploader .weui-uploader__hd .weui-uploader__info {
/* 半透明灰色文字 */
color: rgba(0,0,0,0.3);
}
/* 上传器主体样式 */
.weui-uploader .weui-uploader__bd {
/* 负边距,用于抵消文件项的外边距,实现紧凑布局 */
margin-bottom: -8px;
margin-right: -8px;
/* 隐藏溢出内容 */
overflow: hidden;
}
/* 文件列表容器样式 */
.weui-uploader .weui-uploader__bd .weui-uploader__files {
/* 移除列表默认样式 */
list-style: none;
}
/* 文件项样式 */
.weui-uploader .weui-uploader__bd .weui-uploader__files .weui-uploader__file {
/* 左浮动,实现网格布局 */
float: left;
/* 右边距和下边距,创建文件项之间的间距 */
margin-right: 8px;
margin-bottom: 8px;
/* 文件项尺寸:96x96像素的正方形 */
width: 96px;
height: 96px;
/* 背景图片:使用WEUI提供的默认图片占位符 */
background: url("https://weui.io/images/pic_160.png") no-repeat 50%;
/* 背景图片覆盖整个区域 */
background-size: cover;
}
📄 common.styl
$weui-bg-0 = #ededed
$weui-bg-2 = #fff
$weui-fg-1 = rgba(0,0,0,0.55)
$weui-fg-2 = rgba(0,0,0,0.3)
$weui-fg-3 = rgba(0,0,0,0.1)
*
margin 0
padding 0
.page
position absolute
top 0
left 0
right 0
bottom 0
background-color $weui-bg-0
overflow scroll
-webkit-overflow-scrolling touch
box-sizing border-box
z-index 1
.page__hd
padding 40px
.page__title
text-align left
font-size 20px
font-weight 400
.page__desc
margin-top 4px
color $weui-fg-1
text-align left
font-size 14px
.weui-cells
margin-top 8px
background $weui-bg-2
position relative
overflow hidden
&::before
content ""
position absolute
left 0
right 0
height 1px
background-color $weui-fg-3
z-index 2
.weui-cell
padding 16px
position relative
display flex
align-items center
line-height 1.41176471
.weui-cell__bd
flex 1
.weui-cell__uploader
padding-bottom 24px
.weui-uploader
.weui-uploader__hd
display flex
padding-bottom 12px
align-items center
.weui-uploader__title
flex 1
.weui-uploader__info
color $weui-fg-2
.weui-uploader__bd
margin-bottom -8px
margin-right -8px
overflow hidden
.weui-uploader__files
list-style none
.weui-uploader__file
float left
margin-right 8px
margin-bottom 8px
width 96px
height 96px
background url(https://weui.io/images/pic_160.png) no-repeat 50%
background-size cover
🚀 动手试试看!
- 把以上代码分别保存为
index.html、common.css、common.styl。 - 在浏览器中打开
index.html,你会看到一个完整的 WeUI Uploader! - 修改
common.styl中的变量,比如把$weui-bg-0改成粉色,看看页面颜色变魔术!
🌈 结语:前端思维养成记
写代码不只是“堆砖头”,而是理解为什么这么写!
通过这篇博客,你不仅学会了 WeUI Uploader 的写法,还掌握了:
- BEM命名的“西装打领带”哲学
- 浮动布局的“奶茶店排队”逻辑
- Stylus变量的“快捷键”思维
- 负边距的“魔术师袖口”技巧
- 背景图的“视觉魔术”设计
🎉 现在,去试试写一个属于自己的上传组件吧!如果遇到问题,欢迎留言区“求救”~