组件化
应用➡️
页面➡️
模块➡️
组件➡️
组件与组件之间的关系是组合不是依赖
资源加载路径的层级问题? ../../components/xx/xx.js
组件应该是独立的、无依赖的,如果有耦合,提升到模块的层面。
SPA 在首次加载页面时就获取了所有必需的资源,或者再按需动态加载并且渲染到页面上
base 所有控件只定义基色
基色基础上+1 表示鼠标事件样式 比如,基色为:#fff; 那么鼠标事件样式:#
一个网页是由各种表单、表格、按钮、输入控件等组成,那么从更微观的一个层面去看,这些组件其实都是由线条,线条阴影,圆直角,背景,文字图片内容,留白加上鼠标事件样式构成的。
bootstrap 引入往往千篇一律,如果说它解决了前端开发工程中的有无问题,那么发展到现阶段,应该出现像vui这样最优的选择。
想法:
应该依据html元素在游览器里的渲染顺序
应该定义一套UI设计规范,包含组件的字体,字号,边框,边距,组件间间距
- 定义组件基础样式,边框、边距、字体、字号,每种组件定义大、中、小三种
- theme.css/theme.config 所有组件默认继承theme.css 配色,也可以为每个组件单独定义theme.css主题配色。
- 背景
- color
- :hover样式
- 透明度
- layout
基于24列格柵,
通过flex.layout.css切换flex布局
.col-设置列宽 .col-offset-设置列便宜 col-order-*设置排序
layout
配置文件:
web端
手机端
- flex布局
- 响应式布局
设计模式:
* 导航
* 表单
表单作为获取用户输入的重要交互方式,也承担将问题和答案配对的角色
⚠️注意事项:
- 敏感信息 通过 “输入提示” 说明为什么要这么做 eg: 身份证和电话号码
- 避免在空白中完成输入。通过“默认值”、“输入提示/提醒”、“结构化格式”等方式提示用户
- 即时校错,并尽可能宽容。eg:多输空格默认删掉,不需要提醒用户
包含:标签、输入框、校验反馈、action
交互:
- 对齐方式-按钮组与输入框左对齐 (左对齐、右对齐、顶部对齐)
- 禁用主按钮(输入框3个以下)
- 结构化大格式,不接受偏离期望的格式。 eg:银行卡号输入框
- 输入提示 vs 输入提醒
- 校验 提前开始校验错误,避免点击提交之后才反馈
间距规范:
- 说明文字与表单控件间距 (8px)
- 两组表单控件间距 (横排:16px;竖排:24px)
* 列表
- 获取概览
- 逐项浏览
- 查找特定列表项
- 排序与过滤
- 重新安排、添加、删除或重新分类列表项
交互:
- 显示详情 鼠标悬停某个链接或内容时,显示该项列表少量详情信息 移入0.5s延时
- 列表嵌入 通过点击查看详情信息,显示在当前上下文 两层折叠面板
- 弹层显示
- 面板选择器 通过选择后在右侧弹出该列表大量详情信息
- 单窗口深入
- 分页器
- 无限加载 监听滚轮事件或者单击按钮
* 表格
内容:
- 按钮组
- 搜索
- 排序
- 筛选 (eg:用户上线状态)
- 状态点 (完成、进行中、异常、未开始)
- 单行操作 (更多操作)
- 分页器/无限加载(可选)
交互:
- 显示长表格
- 全选数据
- 跨页选数据
- 固定按钮组
- 过长内容自动隐藏 鼠标悬浮时显示完整
- 表格项编辑 模块编辑 、直接单元格编辑 、悬浮层编辑
间距规范:
行高:
大:表格主体 跟表格标题和分页按钮间距16px,表头上下内边距11px,表格行上下内边距16px、左右边距8px
中:表头与表格行上下内边距为10px
小:表头上下内边距10px,表格行上下内边距6px、左右边距8px
列宽:
表头不换行,固定字节长度大列尽量不换行(时间/操作等)
对齐方式:
数值右对齐,带小数点按小数点对齐;
其余左对齐;
表格增强:
多列数据: 通过按钮实现左右切换;自定义显示列项;固定表头横向滚动显示;
带图标带表格:eg:通过图标表达数据变化趋势
带图表带表格:
二维拓展表格:横向纵向各一个标题
简化表格:卡片和弹出框展示表格
* 搜索
十大设计原则
亲密性 Proximity
信息之间关联性越高距离应该越接近,像一个视觉单元;亲密性的目的是实现组织性,让用户对页面结构和信息层次一目了然。
纵向间距:
- 8px(小号间距)、16px(中号间距)、24px(大号间距)
- 特殊情况可以通过加减『基础间距』的倍数,或者增加元素来拉开信息层次
- y=8+8*n。其中,n>=0,y 是纵向间距,8 是『基础间距』
- 通过增加『分割线』来拉开层次
横向间距:
对齐 Alignment
心理学『格式塔学派』中连续律:在知觉过程中人们倾向于使知觉对象的直线继续成为直线,曲线继续成为曲线。在设计中,将元素进行对齐,既符合用户的认知特性,也能引导视觉流向,让用户更流畅地接收信息。
文字对齐: 字段或段落较短、较散时统一一个视觉起点
表单对齐: 冒号(右)对齐;顺着冒号视觉流,能方便快速填写表单项
数字对齐: 建议取相同有效位数,右对齐;可快速比对数值大小
对比 Contrast
对比增加视觉效果,同时也能在不同元素之间建立一种有组织的层次结构,让用户快速识别关键信息。
重复 Repetition
相同的元素在整个界面中不断重复,不仅可以有效降低用户的学习成本,也可以帮助用户识别出这些元素之间的关联性
线框重复、设计要素重复、文案格式重复。
重复元素可以是一条粗线、一种线框,某种相同的颜色、设计要素、设计风格,某种格式、空间关系等。
直截了当 Make it Direct
需要在哪里输出,就要允许在哪里输入。这就是直接操作的原理。不要为了编辑内容而打开另一个页面,应该直接在上下文中实现编辑。
页内编辑:
单击编辑:当『易读性』远比『易编辑性』重要时,使用单击编辑。
状态一:普通的浏览模式,不区分可编辑行和不可编辑行;
状态二:鼠标悬停时,『指针』变为『手型』,编辑区域底色变黄,出现『Tooltips』提示单击编辑;
状态三:鼠标点击后,出现『输入框』、『确定』、『取消』表单元素,同时光标定位在『输入框』中。
文字链/图标编辑示例
状态一:在可编辑行附近出现文字链/图标;
状态二:鼠标点击『编辑』后,出现『输入框』、『确定』、『取消』表单元素,同时光标定位在『输入框』中
当『易读性』为主,同时又要突出操作行的『易编辑性』时,可使用『文字链/图标编辑』。
简化交互 Keep it Lightweight
足不出户 Stay in the Page
提供邀请 Provide Invitation
巧用过渡 Use Transition
即时反应 React Immediately
推论邀请:用于交互期间,合理推断用户可能产生的需求。
推论邀请示例
用户点击『赞』后,同时系统分析(既然用户喜欢这篇文章,那么可能对这一类文章都有兴趣)并提供开启『精打细算』的邀请。
分析:这里的推论邀请设置不合理方面:‘下次再说’ 应该改为 “3s 后退出/关闭”。虽然推论合理,但你不能代替用户思维。设置自动退出以不影响用户操作。
一个控件有哪几种状态形式?
- 禁止🈲️ state-disabled disabled="disabled"
- 报错❌ state-error
- 成功✅ state-success
- 警告⚠️ state-warning
- 进行中 ⭕️ state-validating
- 其它包括:
- :hover
- :focus
- :active
- :visited
架构:应用-页面-模块-组件
应用-路由-模块-组件(单页应用)
组件间应该是独立的、无依赖的;
app.config.json 配置文件:
- [x] 文件目录组织结构
- [ ] 手机端 or web端
组件模式架构实现思路:
继承机制:
store 概念:组件不是直接从服务端取数据,而是到对应的前端数据缓存中获取数据。缓存与服务端同步。
数据与dom:当数据变动,dom结构自动变动。即把大多数命令式的dom操作简化为配置操作。
components目录下, 一个目录为一个组件,引入方式可以是这样:
<div include=“components/Employee-panel”></div> or
<div include=“components/Employee.html”> or
<div include=“components/Employee.js”>业务模型(纯逻辑)
视图模型(基本也是纯逻辑)
界面层(多是字符串模板)
同一个视图模型搭配不同的界面模板,可以实现视图模型的复用 ;同一个界面模板与不同的视图模型组合,也能直接组合出完全不同的东西 所以这么一来,我们的复用粒度就非常灵活了
框架不关注组件内部实现,关注组件的数据存取接口
框架应当尽可能以web components 为基石
变更检测:通过某种配置的方式,由框架自动添加一些关联,当数据变更的时候,把DOM进行相应修改,又比如,当DOM发生变动的时候,也更新对应的数据
组件同数据间实现一个有限状态机(数据更新前,正在更新,更新之后等等)
服务器推送一条数据——store缓存更新——界面更新前准备——界面更新中——完成更新
提交数据——store缓存更新——界面更新(多个状态步骤)——
|同时——提交服务器——反馈成功与否——通知store——界面状态更新
变更检测的几种实现方式:
存取器封装。对数据进行包装。一种方式是通过geter与seter函数;另一种在一些新的游览器也可以用defineProperty相关方法。
var data = {
name: "aaa",
getName: function() {
return this.name;
},
setName: function(value) {
this.name = value;
}
}脏检测:(angular@1.x)保存数据旧值与新值,事件发生后的数据跟旧数据比对,有不同再触发界面刷新。控制可能导致数据刷新的来源(各种事件);
观察机制:在ES7里引入了Object的observe方法,可以用于监控对象或数组的变动。所谓观察机制,也就是观测对象属性的变更,数组元素的新增,移除,位置变更等等。
观察机制:
DOM也是可以被观察的,但是目前绝大多数双向同步框架都是通过事件的方式把DOM变更同步到数据上。
事件方式的问题:
- 某个文本框绑定了一个对象的属性,框架内部是监控了这个文本框的键盘输入、粘贴等相关事件,然后取值去往对象里写。但是如果你直接myInput.value=”111”,这个变更就没法获取了。可以从HTMLInputELement的原型上去覆盖value赋值,尝试把这种东西也纳入框架管辖范围。
- 另外一个问题,那就是我们只考虑了特定元素的特定属性,可以通过事件获取变更,如何获得更广泛意义上的DOM变更?比如说,一般属性的变更,或者甚至子节点的增删?
- DOM4引入了MutationObserver,用于实现这种变更的观测。
- polymer实现了一个observe-js,用于观测数组、对象和路径的变更
理解一个问题:
界面控件绑定了一个for循环1000次的数据a
for(var i = 0; i<1000; i++){
obj.a+=1;
}
对框架来说,中间过程必须全都舍弃。react使用了虚拟DOM来减少中间的dom操作浪费;界面只响应逻辑变更的结束状态,不响应中间状态。同样,dom的写入应该是一次性写入的(通过DocmentFragment或者innerHTML一次写入整个字符串)
Immutable Date 函数式编程当中的一个概念
其大致理念:任何一种赋值,应该被转化成复制而不是引用。不存在指向同一个地方的引用。
外层数据——list组件(从外层复制一份数据)
外层数据arr改变——同步给内层list组件数据更新——list组件界面跟新
list组件产生操作事件——改变list组件数据——通过immutable data将数据跟外层同步一份
思考一个问题,没有复用度的东西到底需不需要拆出去,成为一个组件?
所谓组件化,其核心意义在于提取真正有复用价值的东西、更好的组织代码结构以及提升可维护性,哪些东西有复用的价值呢?
- 控件
- 基础逻辑功能
- 公共样式
- 稳定的业务逻辑
模版和函数,两种对UI层组件化的处理方式:
- 模版(字符串):用html字符串的方式去表达界面结构,通过代入数据生成真正的界面。只生成html的叫静态模版,同时还生成事件绑定的叫动态模版。
- 函数:react之类。其内部可能还是使用模版,但在外封装一层,可以对不同平台提供相同接口,统一调用方式。
界面模版:
可视为一种配置文件。某一块界面模版描述自身与数据模型的关系。当被解析后,按照设置与数据建立关联,且更新自身所对应的视图。
通过示例来展示某个简单的组件(widget)的演化过程,看它是如何从一个庞大的、缺乏结构性的代码库进化为一个可重用的组件的:
html5 的元数据和微格式:
微格式:一种简单的、开放的数据格式。主要包括hCard,hCalendar,hAtom这几种。
项目整体方案
基础框架
业务代码规划
ui组件规划
样式主题定制
构建方案
协作方式
我们要做的是:分层隔离
ui层(View):
业务逻辑 (Controller/ViewModel):
数据层(Model):Relay/GraphQL/Falcor /super agent / Fetch
falcor 优化前后端通信,将所有的后台数据通过一个虚拟的json提供给前端
自己的理解 graphQL 使用一个GraphQL一次性将一个聚合根传递到前端(比分解成一个个json节省网络开销)
组件化,关注点分离
react 优点
- 以最高效率去更新dom的更新部分
- 数据结构不可变,意味着组件状态不可变,组件变成可重用。
GraphQL的动机:
应该为组件通过声明的方式声明指定的数据,而不是在组件运行中通过命令方式去抓取数据;既然我们不用在组件中去抓取数据,那么可以将这些多次的数据请求放在一起一次性发出一个请求,以获得所必需的数据。这样我们在增加或移除组件时就可以不用考虑跟踪这些组件所需要的后端数据资源。
声明式编程风格 声明你想要什么,不关注细节,eg:一条SQL语句取得我们想要的数据,至于具体如何取得那是数据库的事
命令式编程风格 需指定详细的获取步骤
数据源
远程 请求远程服务获得
本地 纪录用户操作的状态
问题:
远程数据同步 :实时远程请求 or falcor
组件间数据同步:组件共享一个model
远程数据实现缓存和同步?用falcor 图形结构
Model分为datamodel域uimodel , datamodel 关联远程数据源,uimodel 存储本地ui操作数据
组件化开发 vs 模块化开发
目前社区在某种无意识的混淆这两个概念,组件化开发是模块化开发,但模块化开发不能说就是组件化开发;两者的关系是:(组件化>模块化);
组件化问题:
- 组件css作用域隔离
- 主题配色css全局文件
组件应该是一个成品(至少是半成品)的概念,对比汽车行业,整车的制造由各个组件或部件组合而成;单个组件由特定的功能和外观样式组合而成,所以组件并不只是具有某种功能属性,还包括它的外观样式属性。
组件分为基础组件和高级组件,基础组件当然更多的是复用;高级组件更多的是分治;我们做组件化开发是要在基础组件上做高级组件开发。
组件框架本身是基于模块化机制搭建的,模块机制作为组件机制的基础。一个组件是一个模块;