高阶前端框架开发(学习笔记)

高阶函数

function Vue(state) {
  // 用 Vue.js 编写前端页面
}

function React(state) {
  // 用 React.js 编写前端页面
}

function frontend(state, method) {
   // 框架无关的方法和思想
}
frontEnd(data, Vue);
frontEnd(data, React);
  1. 前端框架发展
  2. 但页面应用基础
  3. 框架开发思想

前端框架的开发

这里写图片描述

the World Wide Web begins as a CERN project called ENQUIRE, initiated by Tim Berners-Lee.

  1. HTML
  2. HTTP
  3. URLs
  4. Httpd and WorldWideWeb
  5. The first website
  6. 2016 Turing Award

前端 2005 前

浏览器大战 1 2
JavaScript标准不完善
1995 Java Applet 和 Adobe Flash

JavaScript 工程化

Doug Crockford

  1. JSON (2001)
  2. JsLint (2002)
  3. JsMin (2003)
  4. JavaScript: The Good Parts (2008)

AJAX 2005

用XHR和后端进行一步交互,可以在不刷新页面更新试图,人们重新思考web的形式,到后来的Web但页应用。

GitHub(2008) 前

  • Dojo(2004)
  • Prototype(February 2005)
  • jQuery(January 2006)
  • YUI(February 2006)
  • MooTools(September 2006)

GitHub(2008)后

这里写图片描述

时间节点

这里写图片描述

  1. XHR 引出AJAX奠定单页面 应用的基础
  2. DC(道格) 推动了JS工程化
  3. github 让前端技术迅速发展
  4. Chrome V8 引擎让大量JS 执行变得可行,并催生了Node.js 为前端生态化奠定基础
  5. 随后出现三大SPA 基础与前端规范高速发展

小结

前端历史大体介绍

前端不是太快 而是被压抑

  • 规范的完善
  • 语言的进化
  • 配套设施的完善

第二章节 但页面应用基础

单页应用定义

只加载一个HMTL页面, 并且随着用户的交互汇总,动态加载内容,并且这个过程不刷新页面。

单叶## 标题 ##应用的特点

  • 用户体验较高
  • 节省服务器计算资源
  • 技术门槛
  • SEO 首屏幕渲染

单页应用使用场景

  • ERP CRM 编辑器 管理后台 对IE10 及其一下没有特殊要求
  • 移动端 WEB应用

单页应用基础-history api
用URL 控制试图并且不触发页面刷新

  • Hash
  • HTML5 History API
  • Memory

抽象 history api

  • location:path ,query, hash,[state]
  • push(path,[state])
  • replace(path,[state])
  • go(n) -movers history stack by n entries

服务端渲染 -Router

这里写图片描述

URL页面
/domain/abcABC
/domain/abdABD
/domain/aeAE

单页应用-Router

这里写图片描述

URL页面
/domain/a/b/cABC
/domain/a/b/dABD
/domain/a/b/f/gABFG

单页应用-Routert

这里写图片描述

单页应用Router

这里写图片描述

单页应用-Router

这里写图片描述

Link与菜单设计

这里写图片描述

Router 进阶

  • 权限控制 — 路由钩子
  • 路由代码分块 — 动态路由结合webpack代码分块
  • 404,403 页面 — 路由钩子
  • 页面动画 — 逻辑+动画库
  • URL前缀 — URL 前缀-history api抽象

小结

  • 单页应用的特点和使用场景
  • 单页应用的路由(框架无关)
    • Histroy api
    • Router 设计
    • 进阶的用法

章节

框架开发思想

  • 组件化思想
  • 数据驱动

组件化思想

  • 组件提取原则
  • 组件指责划分
  • 高阶组件

组件提取原则

AB + AC 》 A • ( B + C)

组件指责划分

视图和逻辑解耦

  • 容器业务组件
  • 通用组件

例子

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
<script src="https://lib.baomitu.com/jquery/3.1.1/jquery.js"></script>
  <div id="temperature1"></div>
  <div id="temperature2"></div>
</body>
</html>


//js
function Temperature(selector, C = 0) {
  var container = $(selector);
  container.append(
    `<div>
        <label> 摄氏度 </label>
        <input type="number" class="left"/> = 
        <label> 华氏度 </label>
        <input disabled type="number" class="right"/>
     </div>`
  );
  container = container.find('div').last();

  var leftEle = container.find('.left');
  var rightEle = container.find('.right');


  leftEle.on('input', e => updateValue(e.target.value));

  function updateValue(c) {
    C = c;
    leftEle.val(c);
    rightEle.val(c * 1.8 + 32);
  }
  updateValue(C);
  return leftEle;
}

var a = Temperature('#temperature1', 100);
var b = Temperature('#temperature1', 100);


//js 版本2

function Temperature(selector, left, right, parse, C = 0) {
  var container = $(selector);
  container.append(
    `<div>
        <label> ${left} </label>
        <input type="number" class="left"/> = 
        <label> ${right} </label>
        <input disabled type="number" class="right"/>
     </div>`
  );
  container = container.find('div').last();

  var leftEle = container.find('.left');
  var rightEle = container.find('.right');


  leftEle.on('input', e => updateValue(e.target.value));

  function updateValue(c) {
    C = c;
    leftEle.val(c);
    rightEle.val(parse(c));
  }
  updateValue(C);
  return leftEle;
}

var parseA = v => v * 1.8 + 32;
var parseB = v => v * 2.2046226;
var parseC = v => v * 6.7547;
var parseD = v => v / 6.7547;
Temperature('#temperature1', '摄氏度', '华氏度', parseA, 100);
Temperature('#temperature1', ' 千克', '  磅', parseB, 100);
Temperature('#temperature1', '人民币', ' 美元', parseC, 100);
Temperature('#temperature1', ' 美元', '人民币', parseD, 100);

组件指责划分小结

  • 通用组件应当是失学模型
    • 纯展示组件 无状态组件
  • 容器组件放置业务逻辑

视图和逻辑结构MV* 模型

bootstrap Antd Element

高阶组件

满足以下条件之一可以为认为是高阶组件

  • 使用了其他的组件
  • 接受组件作为参数
  • 基本都是高阶组件

高阶组件

  • 简化配置
  • 抽象行为
  • 抽象数据
  • 抽象样式
  • 抽象…
<Cabinet>
  <Cabinet.Left>
    <SearchBar />
    <Button>批量查询</Button>
    <BusinessSelect />
  </Cabinet.Left>
  <Cabinet.Right>
    <Button>修改配置</Button>
    <Button>新建实例</Button>
    <Button>标签维护</Button>
    <DropdownButton title="实例操作"/>
  </Cabinet.Right>
</Cabinet>
<Fieldset>
  <IDCSearch/>
  <Fieldset.Row>
    {filters.map((filter, i) =>
      <div key={i}>
        <label>{filter.label}</label>
        <Select.Single/>
      </div>
    )}
  </Fieldset.Row>
</Fieldset>

小结

  • 介绍组件化思想的几个要点
  • 抽象思想上类似函数式编程的结合,高阶等概念

数据驱动开发

  • 把问题抽象成数据(完备的)
  • 数据正交化
  • 视图是数据的映射
  • 设计可以用数据驱动的组件
//版本三
function Temperature(selector, left, right, parse, C = 0) {
  var container = $(selector);
  container.append(
    `<div>
        <label> ${left} </label>
        <input type="number" class="left"/> = 
        <label> ${right} </label>
        <input disabled type="number" class="right"/>
     </div>`
  );
  container = container.find('div').last();

  var leftEle = container.find('.left');
  var rightEle = container.find('.right');


  leftEle.on('input', e => updateValue(e.target.value));

  function updateValue(c) {
    C = c;
    leftEle.val(c);
    rightEle.val(parse(c));
  }
  updateValue(C);
  return leftEle;
}

var parseA = v => v * 1.8 + 32;
var parseB = v => v * 2.2046226;
var parseC = v => v * 6.7547;
var parseD = v => v / 6.7547;
Temperature('#temperature1', '摄氏度', '华氏度', parseA, 100);
Temperature('#temperature1', ' 千克', '  磅', parseB, 100);
Temperature('#temperature1', '人民币', ' 美元', parseC, 100);
Temperature('#temperature1', ' 美元', '人民币', parseD, 100);

版本4

function Temperature(selector, left, right, parse, C = 0) {
  var container = $(selector);
  container.append(
    `<div>
        <label> ${left} </label>
        <input type="number" class="left"/> = 
        <label> ${right} </label>
        <input disabled type="number" class="right"/>
     </div>`
  );
  container = container.find('div').last();

  var leftEle = container.find('.left');
  var rightEle = container.find('.right');


  leftEle.on('input', e => updateValue(e.target.value));

  function updateValue(c) {
    C = c;
    leftEle.val(c);
    rightEle.val(parse(c));
  }
  updateValue(C);
  return leftEle;
}

var parseA = v => v * 1.8 + 32;
var parseB = v => v * 2.2046226;
var parseC = v => v * 6.7547;
var parseD = v => v / 6.7547;
var a = Temperature('#temperature1', '摄氏度', '华氏度', parseA, 100);
var b = Temperature('#temperature1', ' 千克', '  磅', parseB, 100);
var c = Temperature('#temperature1', '人民币', ' 美元', parseC, 100);
var d = Temperature('#temperature1', ' 美元', '人民币', parseD, 100);

a.change(updateMessage);
b.change(updateMessage);
c.change(updateMessage);
d.change(updateMessage);

function updateMessage() {
  var message = `
  <div>
    <p>${a.val()}摄氏度 = ${parseA(a.val())}华氏度</p>
    <p>${b.val()}千克 = ${parseB(b.val())}华氏度</p>
    <p>${c.val()}人民币 = ${parseC(c.val())}美元</p>
    <p>${d.val()}美元 = ${parseD(d.val())}人民币</p>
  </div>`;
  $('#temperature2').empty().append(message);
}

updateMessage();

出现重复代码,需要重构了。在编码道路上如履薄冰,为什么渐行渐远

数据是本质,视图是元凶

var data = [
  [100, '摄氏度', '华氏度', 212],
  [100, ' 千克', '  磅', 220.46226],
  [100, '人民币', ' 美元', 675.47],
  [100, ' 美元', '人民币', 14.80]
]

数据驱动之

  • 把问题抽象成数据

    • 数据描述对问题时间轴完备性
  • 数据正交化

    • 数据互不关联
    • 多种正交形式

数据时间轴完备性和正交化

var data = [
  [100, '摄氏度', '华氏度', 212],
  [100, ' 千克', '  磅', 220.46226],
  [100, '人民币', ' 美元', 675.47],
  [100, ' 美元', '人民币', 14.804506491776097]
]
/* 形式二 */
var data = [
  [100, '摄氏度', '华氏度', v => v * 1.8 + 32],
  [100, ' 千克', '  磅', v => v * 2.2046226],
  [100, '人民币', ' 美元', v => v / 6.7547],
  [100, ' 美元', '人民币', v => v * 6.7547]
]
/* 形式三 */
var exchange = 6.7547;
var data = [
  [100, '摄氏度', '华氏度', v => v * 1.8 + 32],
  [100, ' 千克', '  磅', v => v * 2.2046226],
  [100, '人民币', ' 美元', v => v / exchange],
  [100, ' 美元', '人民币', v => v * exchange]
];
  • 产品 :每隔3秒动态获取以下汇率把
  • 开发:数据驱动
var exchange = 6.7547;
var data = [
  [100, '摄氏度', '华氏度', v => v * 1.8 + 32],
  [100, ' 千克', '  磅', v => v * 2.2046226],
  [100, '人民币', ' 美元', v => v / exchange],
  [100, ' 美元', '人民币', v => v * exchange]
];

//版本5

function ConvertInput(selector, C = 0, left, right, parse) {
  var container = $(selector);
  container.append(
    `<div>
        <label> ${left} </label>
        <input type="number" class="left"/> = 
        <label> ${right} </label>
        <input disabled type="number" class="right"/>
     </div>`
  );
  container = container.find('div').last();

  var leftEle = container.find('.left');
  var rightEle = container.find('.right');


  leftEle.on('input', e => updateValue(e.target.value));

  function updateValue(c) {
    C = c;
    leftEle.val(c);
    rightEle.val(parse(c));
  }
  updateValue(C);
  return leftEle;
}
var exchange = 6.75;
var a = [100, '摄氏度', '华氏度', v => v * 1.8 + 32];
var b = [100, ' 千克', '  磅', v => v * 2.2046226];
var c = [100, '人民币', ' 美元', v => v / exchange];
var d = [100, ' 美元', '人民币', v => v * exchange];
var list = [a, b, c, d];

setInterval(()=>{
  exchange = 6.75 + Math.random() *  - .5;
  render()
}, 3000);

function renderMessage() {
  var message = list.map(item => `<p>${item[0]}${item[1]} = ${item[3](item[0])}${item[2]}</p>`).join('\n');
  message = `<div>${message}</div>`;
  $('#messages').empty().append(message);
}
function render() {
  $('#inputs').empty();
  list.forEach(item => ConvertInput('#inputs', ...item).on('input', e => {
    item[0] = e.target.value;
    console.log(item[0])
    renderMessage();
  }));
  renderMessage();
}
render();

使用框架

框架能处理好数据到视图的绑定 目前主流框架都是单项数据流

设计可以用数据驱动的组件

数据驱动从数据出发
组件对数据无侵入

组件对数据无要求Array

const options = [
  {label: 'label1', id: '1'},
  {label: 'label2', id: '2'},
  {label: 'label3', id: '3'}
]
const computedOptions = option.map(i=>({value: i.id, name: i.label})

<Select options={computedOptions} />


//
const options = [
  {label: 'label1', id: '1'},
  {label: 'label2', id: '2'},
  {label: 'label3', id: '3'}
]

<HocSelect options={computedOptions} 
  map={ i=> ({name: i.label, value: i.id}) } 
/>

// --------------------------------

const options2 = [
  ['label1','1'],
  ['label2','2'],
  ['label3','3']
]

<HocSelect options={computedOptions} 
  map={ i=> ({name: i[0], value: i[1]}) } 
/>

组件对数据无要求Tree

const options = {label: 'label1', id: '1', children: [
  {label: 'label2', id: '2'},
  {label: 'label3', id: '3'}
]}

<HocTreeSelect options={computedOptions}
  childrenKey="children"
  map={ i=> ({name: i.label, value: i.id}) } 
/>

// lifting
// 不管 value 是单个还是数组都能工作
[].concat(value)

小结

  • 把问题抽象成数据(完备的)
  • 数据正交化
  • 视图是数据的映射
  • 设计可以用数据驱动的组件

WEB应用挑战和机遇

技术门槛变高
兼容性问题
移动端支持和设计
安全问题
性能和体验期望高

参考文档

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值