Introduction
今天小试牛刀,试着写一个task-panel
,不过涉及的组件有点多,先写好组件部分,再把他们拼装成task-panel
设计需求
结构说明
- 组件由三个
div
模块组成,分别为head
,operator
和card-grid
head
由标题,任务个数,和一个dropdown
组件构成operator
由一个长条按钮creator
和编辑框editor
组成,这两个部分不能同时存在card-grid
由两种卡片组成,一种是未完成的,一种是已完成的
组件说明
dropdown
dropdown
包含三个操作,
- 修改
task-panel
的标题 - 在此
task-panel
后新增一个task-panel
- 删除此
task-panel
注意这个组件与父组件相关联
creator
creator
的功能是显示editor
编辑框,同时自身消失
editor
editor
提供两种按钮,取消与 确定,在其中输入文本后传递给父组件
card
card
代表一项任务
组件实现
dropdown
在组件中,需要为每个menu-item
设置好:text
, :action
和@click
事件绑定
其中action
是为了统一@click
处理的方式,不然menu-item
多了,要为每个组件绑定一个不同的处理函数,详细请看下方行为处理
设计需求
主要功能
显示一个菜单,这个菜单有三个功能,分别是
- 修改
task-panel
的标题 - 在此
task-panel
后新增一个task-panel
- 删除此
task-panel
- 修改
- 这三个功能通过
emit
传递给父组件
组件修饰
- 鼠标悬浮
div.entry
的图标时,图标的颜色加深
- 鼠标悬浮
接口
- 通过
active
属性控制菜单的显示
- 通过
[active == false] 初始状态
[active == true] 激活状态
[行为1] 点击初始状态下的dropdown
方法 toggleHandler
toggleHandler() {
this.$emit('toggle')
},
[行为2] 点击菜单中的条目
handler(action) {
this.$emit('toggle-menu', action)
}
组件修饰
.entry svg.icon:hover {
opacity: 1;
cursor: pointer;
}
// 图标设置
.entry svg.icon {
width: 1em;
height: 1em;
opacity: 0.5;
}
// 设置为相对布局,这样整个菜单的显示以这个为参照
.entry svg.icon {
position: relative;
}
// 菜单栏
div.menu {
/* border: 1px solid black; */
box-shadow: 0 12px 32px 0 rgba(38,38,38,0.16);
border-radius: 4px;
background-color: white;
width: 194px;
position: absolute;
top: 31.5px;
}
// 整体布局
div.dropdown {
display: flex;
flex-direction: column;
align-items: center;
}
creator
设计需求
主要功能
- 点击后使
editor
组件显示,同时自身消失,此时active == true
- 当退出
editor
时,creator
恢复,此时active == false
- 点击后使
组件修饰
- 鼠标悬浮时,
box-shadow
颜色加深,内置图标变蓝
- 鼠标悬浮时,
接口设计
active
控制editor
的显示
基本结构
[行为] 处理点击事件
handler() {
this.$emit('toggle')
},
组件修饰
// icon .creator svg { width: 20px; height: 20px; color: #8C8C8C; } // 整体布局 div.creator { height: 30px; box-shadow: 0 1px 2px rgba(0,0,0,0.1); border-radius: 4px; display: flex; align-items: center; justify-content: center; /* text-align: center; */ background-color: white; margin: 8px 0; } // 鼠标悬浮 div.creator:hover { box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15); cursor: pointer; } div.creator:hover svg#at-plus path { fill: #309fee; }
editor
设计需求
主要功能
- 提供输入文本框和两个按钮控制
- 将输入的文本传递给父组件
组件修饰
- 针对
textarea
标签,鼠标点击进入时,边框变为蓝色- 对两个
button
按钮背景颜色和文字颜色进行设置- 鼠标悬浮在
button
上时,需要button
变换背景色,也可以使用transition
属性添加动画接口设计
holder
控制textarea
中placeholder
的内容rows
控制textarea
的rows
属性大小active
控制自身的显示,v-show="active"
基本结构
组件修饰
- 主要样式
.footer button.cancel { color: #1b9aee; border-color: #ccecff; background-color: transparent; } .footer button.cancel:hover { color: #1b9aee; background-color: #f2fbff; border-color: #ccecff; cursor: pointer; } .footer button.submit { margin-left: 12px; border-style: solid; background-color: #1b9aee; border-color: transparent; color: rgb(255, 255, 255); } .footer button.submit:hover { cursor: pointer; background-color: #0171c2; } .footer button.submit[disabled] { cursor: not-allowed; background-color: #bfbfbf; border-color: #bfbfbf; }
- 次要样式
.editor { width: 100%; /* height: 216px; */ background-color: #fff; box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1); } // textarea textarea { color: #262626; /* padding: 4px 8px; */ font-size: 14px; font-weight: 400; outline: none; border-radius: 4px; border: none; line-height: 20px; resize: vertical; vertical-align: middle; /* width: 230px; */ width: 95%; height: 60px; padding: 4px 8px; } textarea { line-height: 1; vertical-align: middle; border: 1px solid #d9d9d9; } textarea:focus { border-color: #1b9aee; } // 设置 position与display .editor .body { padding: 12px 12px 16px 12px; display: flex; justify-content: center; } // footer .footer { padding: 12px; text-align: right; border-top: 1px solid #E5E5E5; } // 通用button样式 .footer button { border-style: solid; border-radius: 4px; padding: 0 7px; height: 28px; line-height: 26px; font-size: 14px; border-width: 1px; min-width: 52px; display: inline-block; text-align: center; white-space: nowrap; vertical-align: middle; transition: background-color 0.3s ease,color 0.3s ease,border-color 0.3s ease; }
行为设计
submitEditorText() { this.$emit('submit', this.inputText) this.inputText = '' }, cancelHandler() { this.$emit('cancel') },
card
设计需求
主要功能
- 显示任务的状态与任务的描述
- 在组件中,通过点击
span.check-box
图标来控制任务的状态- 不提供细节服务
组件修饰
当
done == 'true'
时,card
整体变灰
- 同时
span.check-box
打勾- 同时横线穿过
card
的文字内容鼠标悬浮时
box-shadow
变深- 整体向下偏移一点
- 同时用动画修饰这些变化
接口设计
done
表示card
的状态,
content
表示card
的任务内容基本结构
{{ content }}行为设计
toggleHandler() { this.$emit('toggle', this.done) },
组件修饰
- 主要部分
/* when card is done */ .card.done .task-content { color: rgb(140, 140, 140); text-decoration: line-through; } .card.done .check-box { fill: rgb(140, 140, 140); } .card:hover { box-shadow: 0 1px 2px 2px rgba(0, 0, 0, 0.1); transform: translateY(2px); cursor: pointer; } .check-box:hover svg { fill: #595959; }
- 次要部分
.card { display: flex; align-items: center; font-size: 14px; height: 48px; } .card span.check-box { width: 20px; height: 20px; margin: 0 12px; } // style of task content /* structure of task content */ .task-content { max-width: 172px; font-size: 14px; line-height: 20px; } /* display of task content */ .task-content { display: flex; flex-grow: 1; flex-shrink: 1; } // whole card color .card { box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1); background-color: white; border-radius: 4px; transition: transform 0.2s; } // last: distance of each card .card { margin-bottom: 8px; }