diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..ec6d3cdd7f --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +package.json diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..986a0ad728 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,33 @@ +> 在修改文档之前,请先阅读此文章 + +### 目录结构 + +``` +- foo.md 文档内容, 可以有文件夹嵌套 +- yoo.md +``` + +### 文档结构 + +```markdown +--- +title: 文档标题(必须有) +order: 可选, 文档顺序, 数字越小越在前面, 否则按照字母序 +hide: 可选, 布尔值, 是否隐藏文档 +category: 可选, 字符串, 一级分类 +cover: 可选, 建议有, 封面图 +--- + +markdown 格式的文档内容 +``` + +### 词汇表述 + +请注意大小写和复数形式 + +* `ICE`: 品牌名, 中文称之为 `飞冰` +* `Iceworks`: 配套 GUI 软件 +* `物料 - marterial`: 包含区块, 布局, 模板和组件 +* `区块 - block`: 复用的最小代码片段 +* `布局 - layout`: 为 ICE 提供整体布局方案的代码 +* `模板 - scaffold`: 整站示例, 脚手架 diff --git a/docs/about.md b/docs/about.md new file mode 100644 index 0000000000..255e040e3e --- /dev/null +++ b/docs/about.md @@ -0,0 +1,40 @@ +--- +title: 关于 ICE +order: 1 +cover: https://gw.alicdn.com/tfs/TB1vBRYaVOWBuNjy0FiXXXFxVXa-2558-1306.jpg +--- + +## 目标和愿景 + +ICE 是一套基于 React 的中后台应用解决方案,在阿里巴巴内部,已经有 270 多个来自几乎所有 BU 的项目在使用。经过 2 年的发展,ICE 已经是中后台 2.0 体系,这个阶段中我们的目标是赋能企业、组织搭建自己的中后台体系。ICE 包含了一条从设计端到开发端的完整链路,帮助我们的用户快速搭建属于自己的中后台应用。 + +我们希望中后台应用的开发能变得更高效。面向**设计者**端,我们提供了 ICE Design 设计语言,来给我们的 UI 界面提供专业的视觉指导。面向**开发者**端,我们提供了 Iceworks 工具,这是一个图形化界面的开发平台,它承载了 ICE 的物料体系和开发体验,获取更多信息您可以立即[点击这里](#/iceworks)下载体验。同时,我们还提供了独有的**服务体系**,在物料与工具这一基础之上进行服务的配套。我们将构建一个面向开发者的服务体系。针对每一个使用 ICE 体系的企业或个人,我们会安排专人客服进行一对一的对接,一旦有问题可以随时找到我们,第一时间帮助解决问题。 + +## 初心 + +在整个阿里体系内,面向卖家、运营小二以及达人有数不尽的后台,并且这些后台一直在持续不断的增长着,但是随着时间的推移,这些项目或多或少的存在着以下这些问题: + +* 每个后台相互独立,同类功能也需要重复开发,前期开发成本较高 +* 技术方案差异大,人员变动后维护成本非常高 +* 视觉质量参差不齐,使用效率大打折扣 +* ... + +ICE 就是为了解决这些问题而诞生。ICE 由淘宝前端团队发起,与淘宝 UED 及后端开发同学共同打造,旨在「提高中后台系统的开发效率」。 + +## 物料体系 + +在 ICE 中,组件、区块、布局、模板等统称为物料,由 ICE 团队维护,在内部有一套完整的开发规范和工具,目前也正在逐步对外开放中;基于此,你可以参与共建 ICE,也可以自建私有的物料体系。 + +* 组件:最基础的物料,目前 ICE 的基础组件达到 55+,具有高度可复用性。 + +* 区块:通过对大量的中后台系统常用的场景进行分类、对比和抽象,基于基础组件组合而成,目前 ICE 的区块达到 110+,可以通过 iceworks 进行快速组合搭建应用,减少重复的开发,提升效率。 + +* 布局:在中后台系统中布局通常较为统一,以 `顶部-侧边布局-通栏` 模式为主,为此我们提供了 4+ 常见的布局,支持 `light` 和 `dark` 两套主题。 + +* 模板:基于已有的区块搭建而成,目前提供了 4+ 的特定领域的模板,可以从零开始搭建应用,也可以选择特定类型的模板开始使用。 + +## 联系我们 + +* 邮件: +* 反馈/建议: +* 答疑钉钉群: diff --git a/docs/advanced/how-to-make-form.md b/docs/advanced/how-to-make-form.md new file mode 100644 index 0000000000..6033aa73a2 --- /dev/null +++ b/docs/advanced/how-to-make-form.md @@ -0,0 +1,223 @@ +--- +title: 如何制作表单 +order: 4 +category: 进阶指南 +--- + +在中后台前端应用中,表单是一个非常常见的需求,用于填写一些信息、校验、编辑、提交等。本文档专门介绍如何使用 ICE 快速实现常见的后台表单类需求。 + +为了简化使用,提高开发效率,我们推荐使用 ICE 表单粘合剂组件 `@icedesign/form-binder` 配合 ICE 提供的一系列表单类组件(如 Input, Select 等) 的组合来进行开发。 + +在这里我们准备了非常常见的业务场景作为演示,**模态框 + 表格 + 表单** 组合的业务场景。 + +![](https://img.alicdn.com/tps/TB1GZQhNFXXXXatXpXXXXXXXXXX-1420-506.png) + +在各个表单组件包裹 `FormBinder` 组件,并声明对应的 `name` `FormBinder` 会自动与这些组件的数据进行关联,之后我们就要利用 `FormBinder` 自带的功能进行获取、校验、回填处理。 + +## 回填数据 + +在使用 `FormBinder` 组件后,我们不需要为单独的表单组件(如 Input,Radio 等)进行 value 值的回填。我们可以在 `FormBinderWrapper` 上用 `value` 统一进行回填,使用对象的形式,其中键值会自动与 `FormBinder` 上的 `name` 进行关联,就像 HTML5 标准表单一样: + +```jsx +import { + FormBinderWrapper, + FormBinder, + FormError, +} from '@icedesign/form-binder'; + + +
+ + + + + + + + + + + + + + + + + + +
+
+``` + +由于 Form 此时是一个受控组件,清空数据等操作可以对 `value` 赋空值进行: + +```jsx +class Demo extends Component { + state = { + formValue: { + id: '1' + name: '卓凌', + age: 20, + sex: 'male' + } + }; + + clearForm = () => { + this.setState({ + formValue: {} + }); + }; + + render() { + return ( + +
+ + + + + + + + + + + + + + + + + + + +
+
+ ); + } +} +``` + +## 主动触发校验 + +如果想要主动校验全部表单,则需要在 FormBinderWrapper 组件上面添加 ref,在合适的地方调用实现,全部校验发现报错表单会自动跳转到对应表单。 + +```jsx +import { + FormBinderWrapper, + FormBinder, + FormError, +} from '@icedesign/form-binder'; + +validateForm = () => { + this.form.validateAll((errors, values) => { + console.log('errors', errors, 'values', values); + }); +}; + + { this.form = ref; }} + value={value} + onChange={this.formChange} +> + ... + + +``` + +### 校验规则的类型陷阱 + +在前端开发中,有一些类型陷阱是需要开发者特别注意的。用户输入的 `Input` 等,它的类型默认都是字符串 `String`,当然你可以回填一个 `Number` 类型的数据给 `Input`,但是在取值的时候它会被转换成字符串。 + +```jsx + + + +``` + +## 总结 + +至此,已经讲解完了如何使用 `FormBinder` 组件并进行相关操作,以及可能遇到的问题。简单的回顾: + +1. 首先使用 `FormBinderWrapper` 包裹所有表单项。 +2. 在 `FormBinder` 组件上使用 `name` 进行数据关联,配置校验规则。 +3. 使用 `FormBinderWrapper` 的 `value` 属性进行数据回填。 +4. 使用 ref 上的 `valildateAll` 方法校验当前表单数据并进行后续操作。 + +## FAQ + +### Q:表单作为一个子组件的时候,我怎么把需要回填的值传递下去并回填? + +React 组件有一个生命周期 componentWillReceiveProps 是在当前组件 props 变动的时候触发,此时可以在这个生命周期方法中传递 value: + +```jsx +class Demo extends React.Component { + + ... + + state = { + formValue: {} + }; + + componentWillReceiveProps(nextProps) { + // nextProps 是上层传下来需要回填的数据 + if(nextProps.name) { + const { formValue } = this.state; + this.setState({ + formValue: { + ...formValue, + name + } + }); + } + } + + render() { + return ( + ... + ); + + } +} +``` + +### Q:如何在表单组件 onChange 的时候做一些额外的事情? + +直接使用表单组件的 `onChange` 或者 FormBinderWrapper 的 `onChange` 即可,没有任何魔法。 + +```jsx +handleInputChange = (input) => { + console.log('Input 的值现在是', input); +}; +// ... +; +``` + +```jsx +handleFormChange = (value, changedByName) => { + const changedValue = value[changedByName]; + console.log('由于' + changedByName + '变成了' + changedValue); + console.log('表单的值现在是', value); +}; +// ... + +
+ + + +
+
; +``` diff --git a/docs/advanced/version-rules.md b/docs/advanced/version-rules.md new file mode 100644 index 0000000000..280d0bf521 --- /dev/null +++ b/docs/advanced/version-rules.md @@ -0,0 +1,89 @@ +--- +title: 组件版本号规则说明 +order: 2 +category: 进阶指南 +--- + +## 版本号规则 + +组件的版本以 `major.minor.patch` 形式表示 `主版本号.次版本号.修订号` 比如: `0.1.0` `0.3.1`。 + +版本号递增规则如下: + +1. 主版本号:不兼容的 API 修改, +2. 次版本号:向下兼容的功能性新增, +3. 修订号:向下兼容的问题修正。 + +## 版本控制规范 + +目前项目内用到的主要有以下两种规则: + +### patch 位自动升级 + +标识符:`~` + +依赖版本表示为 `~0.1.0` + +如: + +```js +{ + "dependencies": { + "foo": "~2.0.0" + } +} +``` + +当 `foo` 发布了 `2.0.30` 版本,表示做了向下兼容的问题修正(BUG fix 等), 在开发与构建时则会安装 `2.0.30`。 + +如果 `foo` 存在 `2.1.0` 版本,根据标识符 `~` 也不会安装此版本。 + +#### 优点: + +自动更新升级项目内组件依赖版本(patch),当组件开发者发布了新版本修复存在的现有问题,可自动升级。 + +### minor 位自动升级 + +标识符:`^` + +依赖版本表示为 `^0.1.0` + +> 温馨提示:包含 patch 自动升级 + +如: + +```js +{ + "dependencies": { + "foo": "^2.0.0" + } +} +``` + +当 `foo` 发布了 `2.0.30` 版本,表示做了向下兼容的问题修正(BUG fix 等), 在开发与构建时则会安装 `2.0.30` + +如果 `foo` 存在 `2.1.0` 版本,根据标识符 `^` 则会安装 `2.1.0`。 + +#### 优点: + +自动更新升级项目内组件依赖版本(minor),当组件开发者发布了新的特性、API 等,可升级到相应的版本。同时也包含升级 (patch)的功能。 + +### 固定版本号 + +固定版本号则需要项目开发者维护版本依赖,无标识符。 + +如: + +```js +{ + "dependencies": { + "foo": "2.0.0" + } +} +``` + +表示只安装 `foo` `2.0.0` 版本,不会在开发与构建时安装其他版本。 + +#### 优点: + +项目内的组件依赖都是固定的版本,完全保证项目代码一致性。如当组件含有 BUG 时,需开发者手动刚更新组件依赖的版本。 diff --git a/docs/advanced/webstorm-config.md b/docs/advanced/webstorm-config.md new file mode 100644 index 0000000000..ba45d89019 --- /dev/null +++ b/docs/advanced/webstorm-config.md @@ -0,0 +1,59 @@ +--- +title: WebStorm 推荐配置 +order: 1 +category: 进阶指南 +--- + +如果您使用 WebStorm 来进行项目的开发,我们还推荐配置如下插件,进一步提升你开发前端的流畅度。 + +## 配置功能点 + +### 代码自动格式化工具 Prettier + +Prettier 是针对 React 语法推出的代码格式化工具,基于 AST 精准分析,代码格式化速度快更加准确。 + +#### 第一步:安装 Prettier 工具 + +打开命令行,直接执行 `npm install prettier -g` 即可。 + +#### 第二步:打开 IDEA External Tools 配置界面 + +打开 IDEA 找到 Settings 面板,搜索 external 即可找到 `External Tools` 工具。 + +![](https://img.alicdn.com/tfs/TB1KaqTSpXXXXabXpXXXXXXXXXX-1022-676.png) + +#### 第三步:添加相关命令调用配置 + +点击 External Tools 右侧 `+` 即可打开配置界面: + +* Program 设置为 `prettier` +* Parameters 设置为 `--write --single-quote --trailing-comma es5 $FilePathRelativeToProjectRoot$` +* Working directory 设置为 `$ProjectFileDir$` + +![](https://img.alicdn.com/tfs/TB1Oai4SpXXXXXTXXXXXXXXXXXX-987-493.png) + +配置完成之后,摁下快捷键 Cmd-Shift-A(OS X)或者 Ctrl+Shift+A(Windows、Linux)唤起命令执行窗口,然后输入 `prettier` 回车即可进行格式化。 + +![](https://img.alicdn.com/tfs/TB18_5GSpXXXXbxXFXXXXXXXXXX-1226-540.png) + +#### 第四步:配置自动格式化 + +通常可以配置文件变动自动格式化功能,这里就需要配置 `File Watcher` 了。 + +首先先需要安装 File Watchers 插件: + +![](https://img.alicdn.com/tfs/TB1ciKgSpXXXXbAapXXXXXXXXXX-1451-679.png) + +之后,我们来配置文件变动监听之后的执行命令。打开 Settings 面板,搜索 file watchers 即可打开 `File Watchers`,点击右边 `+` 新建配置: + +* File type 通过下拉找到 `React JSX` 文件。 +* Scope 可以选为 `All Places`。 +* Program 设置为 `prettier` +* Arguments 设置为 `--write --single-quote --trailing-comma es5 $FilePath$` +* Output paths to refresh 设置为 `$ProjectFileDir$` + +![](https://img.alicdn.com/tfs/TB1O_5QSpXXXXaZXpXXXXXXXXXX-1022-676.png) + +之后,当你编写 React JSX 代码时,就会自动进行格式化纠正,效果如下: + +![](https://img.alicdn.com/tfs/TB1oiOZSpXXXXbDXXXXXXXXXXXX-600-376.gif) diff --git a/docs/basis/api-communicate.md b/docs/basis/api-communicate.md new file mode 100644 index 0000000000..af4c26cb65 --- /dev/null +++ b/docs/basis/api-communicate.md @@ -0,0 +1,125 @@ +--- +title: 如何实现前后端通信 +order: 9 +category: 入门指引 +--- + +实现前后端通信,我们推荐使用 axios 或 DataBinder 与后端 HTTP API 接口通信的方案。 + +传输数据格式描述使用 JSON。 + +## 使用 axios 进行请求 + +ICE 推荐使用 axios 方法库提供基础的 Ajax 能力,也可以使用 DataBinder 为组件(比如 Table)绑定 AJAX 接口数据,方便查询异步数据以及错误处理。 + +首先安装模块: + +```bash +npm install axios +``` + +引入对应组件,并使用 `axios` 函数获取数据: + +```jsx +import axios from 'axios'; + +export default class extends Component { + componentDidMount() { + // 使用 axios 获取数据 + axios(remoteURL).then((response) => { + const { body } = response; + this.setState({ + data: body, + }); + }); + } + + render() { + // ... + } +} +``` + +> 更多请参考 [axios 的文档](https://github.com/axios/axios) + +## 使用 DataBinder 为组件绑定数据 + +DataBinder 是 ICE 推出的基于约定,在组件上绑定数据和自动更新数据的组件,让你专注于 UI 显示逻辑,从而屏蔽数据状态管理的开发成本。 + +**使用方法** + +```jsx +@DataBinder({ + '模块名 key': { + url: 'xxxx.json', + method: 'post', + // 请求附带的 request 参数,method post 下是 data 参数,method get 下是 params + data: { + page: 1, + }, + // AJAX 部分的参数完全继承自 axios ,参数请详见:https://github.com/axios/axios + // 下面是请求会返回的默认数据 + defaultBindingData: { + // ...字段需要与 xxxx.json 接口返回的字段一一对应 + }, + }, +}) +class ListView extends Component { + // ... + render() { + const { account } = this.props.bindingData; + + return ( +
+

用户名:{account.userName}

+

年龄:{account.userAge}

+
+ ); + } +} +``` + +> 更多请参考 [DataBinder 的文档](#/component/databinder) + +## 最佳实践 + +对于一些嵌套较深的对象数据,如果后端返回为空,就可能导致渲染异常,所以需要进行先行判断: + +**注意:以下是错误的用法** + +```js +this.setState({ + foo: data.list.foo, +}); +``` + +**最佳实践** + +```js +if (data && data.list && data.list.foo) { + this.setState({ + foo: data.list.foo, + }); +} else { + // foo 未取到 +} +``` + +## 同源限制导致的跨域问题 + +浏览器安全的基石是"同源政策",所谓"同源"指的是"三个相同"。 + +* 协议相同 +* 域名相同 +* 端口相同 + +举例来说,`http://www.example.com/dir/page.html`这个网址,协议是`http://`,域名是`www.example.com`,端口是`80`(默认端口可以省略)。它的同源情况如下。 + +* `http://www.example.com/dir2/other.html`:同源 +* `http://example.com/dir/other.html`:不同源(域名不同) +* `http://v2.www.example.com/dir/other.html`:不同源(域名不同) +* `http://www.example.com:81/dir/other.html`:不同源(端口不同) + +同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。 + +跨域指的是前端页面请求一个非同源的 API 地址,这种请求一般来说会被浏览器阻挡。 diff --git a/docs/basis/env-config.md b/docs/basis/env-config.md new file mode 100644 index 0000000000..530f4bdf54 --- /dev/null +++ b/docs/basis/env-config.md @@ -0,0 +1,39 @@ +--- +title: 开发环境配置 +order: 1 +category: 入门指引 +--- + +ICE 的开发环境依赖于 Node.js,如您已经安装了 Node.js 且版本号符合 \*LTS 版本,则可以忽略此文档。 + +### 安装 Node.js 环境 + +#### macOS 用户 + +我们建议您使用 \*nvm 来管理 Node.js 的安装。 + +打开终端,执行如下命令 + +```bash +curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash +``` + +完成后重启终端,执行 `nvm install --lts` 来安装最新 LTS 版本的 Node.js + +#### Windows 用户 + +访问 Node.js 的官网,下载对应平台且标记为 LTS 版本的安装包,并执行安装,安装成功后在终端执行: + +### 验证安装的 Node.js 版本 + +在终端中执行如下命令 (Windows 下可以是 Git Bash 或其它终端模拟器) + +```bash +node -v +npm -v +``` + +终端打印出 Node.js 和 npm 的版本,则表示安装成功。 + +> * LTS: 指的是 Node.js 的长期维护版本,您可以在这里 https://github.com/nodejs/Release#release-schedule 看到 Node.js 各版本的官方持续维护期限 +> * nvm: 请参考 https://github.com/creationix/nvm diff --git a/docs/basis/find-components.md b/docs/basis/find-components.md new file mode 100644 index 0000000000..7cb8c54f74 --- /dev/null +++ b/docs/basis/find-components.md @@ -0,0 +1,23 @@ +--- +title: 如何查找社区组件 +order: 11 +category: 入门指引 +--- + +ICE 组件体系基于 NPM 包管理,因此除了我们提供的高质量组件之外,你还可以自行检索使用 NPM 社区里超过 37w+ 的组件,下面介绍下通常我们是怎么查找这些组件拿来用的。 + +#### 1. 使用英语在 google 或者 github 站点上检索 + +优质的组件往往会采用英语(为了服务全世界,很多中国人开发的也是用英语介绍),所以针对你的需求使用英文关键词会极大的提升检索效率和结果质量。 + +比如我们希望找到管理 react state 更好的方案或者库,可以试着搜索 "react state management github" 或者 "react state management npm" 可以找到几个选项,其中可以看到 [mobx](https://github.com/mobxjs/mobx) 在 github 上面有非常多的 star,证明这个包比较可靠、使用者比较多,可以优先选择使用。 + +#### 2. 查找文档找到安装方法和使用方法 + +目前前端相关的项目,基本都会提供 NPM 的安装方式,基于 NPM 进行包管理。查找文档你可能会看到类似这样的安装说明: + +![](//img.alicdn.com/tfs/TB14B7YOVXXXXcRXpXXXXXXXXXX-1914-982.png) + +通常来说,组件的安装方式是执行命令 `npm install [package name] --save`。 + +之后需要参照相关文档进行使用,如果你觉得符合你的需求挺好用,欢迎推荐给我们补充到站点上面。如有问题也可以随时咨询。 diff --git a/docs/basis/git-assets-work.md b/docs/basis/git-assets-work.md new file mode 100644 index 0000000000..d6937abe08 --- /dev/null +++ b/docs/basis/git-assets-work.md @@ -0,0 +1,75 @@ +--- +title: Git 仓库开发实践 +order: 3 +category: 入门指引 +--- + +使用 Iceworks 创建项目后,会自动生成项目的脚手架文件,下面就对这些文件的仓库管理进行说明。 + +## 目录结构 + +以 `Ice Design Pro` 模板为例: + +``` +ice-design-pro +├── dist // 打包资源 +├── mock // 模拟数据 +├── public // 静态资源 +├── src +│ ├── components // 公共组件 +│ ├── config // 公共配置 +│ ├── layouts // 通用布局 +│ ├── pages // 页面 +│ ├── index.js // 应用入口 +│ └── routes.jsx // 路由入口 +├── tests // 测试 +├── .editorconfig // 代码风格配置 +├── .eslintignore // eslint 忽略目录配置 +├── .eslintrc // eslint 配置 +├── .generator.json // 区块配置 +├── package.json // package-lock.json +├── package.json // package.json +└── README.md // 项目说明 +``` + +## 使用命令行操作 + +这里介绍使用命令行操作 git 仓库的基本命令,如果您使用 GUI 工具 (如 SourceTree) 进行管理,请遵循该工具的帮助文档。 + +### 初始化 Git 仓库 + +在初始化的项目根目录下执行以下命令,并将初始化的文件推送到 git 仓库: + +```bash +$ git init +$ git add . +$ git commit # 输入提交信息并保存 +``` + +### 2. 提交项目到远程 Git 仓库 + +您需要使用 github 或者 gitlab 创建一个远程仓库,由于 Git 是一种分布式仓库管理工具,如果您打算只在本地使用这些代码, 那么可以忽略这一步。 + +```bash +$ git remote add origin git://your-repo-url +$ git push origin master -u +``` + +## 分支管理 + +Git 仓库创建好后,此时只有一个 master 主干,不允许向 master 提交代码,后续开发都应该创建分支在分支上开发。 + +### 创建新分支 + +创建一个名为 feature/0.1.0 的分支。并将分支提交到 gitlab 仓库上。 + +```bash +$ git checkout -b feature/0.1.0 # 创建分支 +$ git push origin feature/0.1.0 # 提交分支 +``` + +这样就创建好一个名为 daily/0.1.0 的分支了。 分支名是可以任意定义的,比如你可以创建自己的功能命名的分支, 如 `git checkout -b feature/add-login` 表示一个登录功能的分支。 + +### 提交变更代码 + +在编写代码完成后,或者某个功能完成时,可以将变更的代码提交到远端分支,准备部署发布。 diff --git a/docs/basis/intro-javascript.md b/docs/basis/intro-javascript.md new file mode 100644 index 0000000000..f972506a74 --- /dev/null +++ b/docs/basis/intro-javascript.md @@ -0,0 +1,406 @@ +--- +title: JavaScript 基础知识 +order: 4 +category: 入门指引 +--- + +写前端必须要掌握一定基础的 JavaScript 语言知识,本文档将介绍绝大部分常用的 JavaScript 语言基础知识,同样概念添加 Java 语言对比,帮你快速学习理解。 + +## JavaScript 语言概述和开发环境、运行环境配置 + +JavaScript 是一门脚本语言,用在网页上增强页面功能,是一门动态语言因此不需要进行编译、部署。 + +JavaScript 是弱类型的语言,语法比较简单,掌握基本语法之后怎么写都可以,比 Java 灵活的多,同时不需要依赖 IDE,任何文本编辑器都可以进行开发。当然如果你用 IDEA 等 IDE 更是锦上添花。 + +JavaScript 比较常见的运行环境就是 Web 浏览器,比如 Chrome 直接打开 console 输入 JavaScript 代码即可运行实时看到结果: + +![](https://img.alicdn.com/tps/TB1tLD7NFXXXXbmXpXXXXXXXXXX-992-616.png) + +> 提示:在 Chrome 中,右击网页选择『检查』即可打开开发者工具,可以切换到 console 面板。详情可以看[如何使用控制台](https://leeon.gitbooks.io/devtools/content/learn_basic/using_console.html)。 +> 提示:控制台比较常用的有 console.log 方法,它可以打印一些内容、变量值等到你的控制台辅助开发,等同 Java 中的 System.out.println 方法。 + +## JavaScript 语法基础 + +### 变量定义 + +* let 定义普通变量(推荐),详情:http://es6.ruanyifeng.com/#docs/let#let命令。 +* const 定义常量,后面只能读不能写,详情:http://es6.ruanyifeng.com/#docs/let#const命令。 +* var 定义普通变量,不建议使用。 + +var 由于缺失某些特性,不建议使用,关于 let 和 var 的对比,详情见:https://www.zhihu.com/question/47456978 。 + +由于 JavaScript 是弱类型语言,因此你不需要声明变量的数据类型。 + +JavaScript: + +```js +let x = 20; +``` + +Java: + +```java +float x = 20.0; +double x = 20.0; +int x = 20; +``` + +具体支持的数据类型参照下面文档。 + +### 数据类型 + +数据类型基础知识详见:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Data_structures ,这里针对常用的几种进行重点讲解。 + +基础类型包括:Undefined、Null、Boolean、Number、String,引用类型包括:Object、Array、Function。当一个变量值为引用类型的时候,直接赋值其他变量传递的是引用。同样的,引用的数据在某个地方改变了值会影响所有调用这个变量的地方。这跟 Java 里面引用概念一样。 + +#### undefined 和 null + +声明一个变量没有赋值,直接访问当前变量可以得到 `undefined`。不同于 Java 针对不同数据类型有不同的初始值: + +JavaScript: + +```js +let x; +console.log(x); // -> undefined +``` + +Java: + +```java +int x; +System.out.println(x); // -> 0 +``` + +访问一个对象上不存在的 key 也会取到 undefined。 + +```js +let a = {}; +console.log(a.b); // -> undefined +``` + +null 表示空值。它不同于 undefined,它是有值的只不过是一个空值,而 undefined 是未定义的临时兜底的缺省值。undefined 和 null 具体的区别请参见:http://www.ruanyifeng.com/blog/2014/03/undefined-vs-null.html 。 + +#### number、boolean、string + +基本的数据类型: + +```js +console.log(typeof 10); // -> number +console.log(typeof '10'); // -> string +console.log(typeof true); // -> boolean +console.log(typeof "true"); // -> string +``` + +JavaScript 中带引号的均为字符串,可以是单引号也可以是双引号。不同于 Java 字符串只能使用双引号表示。JavaScript 没有 int、float 和 double 之分。 + +#### array + +数组类型,栈结构,有序数组。每个 item 可以是任意类型的值,数据类型类似 Java 的 ArrayList ,比如: + +```js +// 字符串数组 +['string', 'aaa'] + +// 对象和字符串混合数组 +[{ + aa: 'aaa', + bb: 'bbb', +}, 'string'] + +// 函数数组 +[() => { + return '这是一个函数' +}, () => { + return '这是一个函数' +}] +``` + +如果需要取得特定需要的值,直接获取(比如获取第一个数据): + +JavaScript: + +```js +array[0]; +``` + +Java: + +```java +list.get(0); +``` + +数组是有序的,遍历数组需要使用流程控制语句 for 等。为了方便,array 内置了一些数组常用操作方法可以简化常用操作,详情可见:。 + +比较常用 [forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) 和 [map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) 方法,可以重点关注下用法。 + +简易循环举例: + +JavaScript: +```js +let list = []; +list.push('aa'); +list.push('bb'); + +for(let i=0; i { + console.log(val, i); +}); +``` + +Java: + +```java +List list = new ArrayList(); +list.add('aa'); +list.add('bb'); + +for(int i=0; i { + System.out.println(val); +}); +``` + +相比 Java 的 add 操作,JavaScript array 的出栈入栈删除的方法名略有不同,常见的 push 入栈、pop 出栈,具体的参照 http://javascript.ruanyifeng.com/stdlib/array.html 。 + +#### object + +对象类型,无序,需要指定 key 等信息关联值,类似 Java 的 HashMap,比如: + +JavaScript: + +```js +let obj = { + name: 'string 字符串', + home: { + province: '山东' + } +}; + +obj.age = 18; + +console.log(obj.home.province); +let key = 'age'; +console.log(obj[key], obj['age']); +delete obj.name; +``` + +Java: + +```java +HashMap obj = new HashMap(); +obj.put('age', 18); + +obj.get('age'); +obj.remove('age'); + +``` + +如果不确定 key 的值(变量)可以使用如下方法调用: + +```js +let key = 'age'; +obj[key]; // -> 18 +``` + +因此可以用来做 key value 的数据映射使用。由于弱类型存储的值可以多种多样,比 Java 使用起来要容易一些。详情: + +#### function + +函数类型,用来创建一个函数,通常会返回一个数据。 + +JavaScript: + +```js +function fun(a, b) { + return a + b; +} +fun(1, 2); // -> 3; +``` + +Java: + +```java +public static int fun(int a, int b) { + int result; + result = a + b; + + return result; +} +fun(1, 2); +``` + +函数是一个可执行的小程序,根据参数处理一些逻辑并返回一段新的数据,在 JavaScript 中用非常多,为此 ES6(新版 JavaScript 语言规范)新增了箭头函数语法,用来简化函数书写: + +```js +let add = function(a, b) { + return a + b; +}; + +等同于 + +let add = (a, b) => { + return a + b; +}; + +循环语句中也非常直观方便: + +list.forEach((a, b) => { + console.log(a + b); +}); +``` + +箭头函数有个重要的特点就是自动绑定了当前的作用域,作用域的概念,JavaScript 和 Java 的一样,JavaScript 中可以使用 bind、call、apply 三个方法改变函数执行的作用域,简单区别如下: + +* bind 方法,创建一个新的函数的**引用**并绑定到一个作用域特定作用域上面,同时支持传参。`bind(作用域对象, 参数1, 参数2)` +* apply、call 方法,直接调用执行该函数,在执行的时候将函数内部的作用域绑定到参数指定的作用域。`call(作用域)` + +这几个方法详情请见: 。通常可能会在 JavaScript 的作用域上产生疑惑,没关系随时联系 ICE 小组进行处理解答。 + +箭头函数声明和特性: + +函数作用域: + +设置函数参数的默认值: + +#### 类型转换 + +类型转换可以通过调用类型的类进行转换,比如将变量 a 转换成 Number 类型,可以使用: + +JavaScript: + +```js +let a = '10'; +a = Number(a); +``` + +Java: + +```java +int x; +(double)x; +``` + +除了这种比较正规的方法之外,跟 Java 一样还有其他惯用方法进行转换。 + +##### 转换 number 类型 + +JavaScript: + +```js +let a = '12.33'; +console.log(parseInt(a)); // -> 12 number +console.log(parseFloat(a)); // -> 12.33 number +``` + +Java: + +```java +int i = Integer.parseInt(“123”); +``` + +##### 转换 string 类型 + +同 Java 每个类型的值都含有 toString() 方法。 + +```js +let a = 12.33; +console.log(a.toString()); // -> '12.33' + +将 Object 转成 JSON 字符串 + +let obj = { + a: 'aa', + b: 'bb' +}; +console.log(JSON.stringify(obj)); // -> '{"a":"aa","b":"bb"}' +let objStr = '{"a":"aa","b":"bb"}'; +console.log(JSON.parse(objStr)); // -> {a:"aa", b:"bb"} +``` + +##### 转换 boolean 类型 + +JavaScript 中的 boolean 的值比较多,空字符串、数字 0、null、undefined 均为布尔值的 false。此外 `!` 表示取当前布尔值的反值,可以通过 `!!` 巧妙的将值转换成布尔值类型的数据。 + +JavaScript: + +```js +console.log(!!'a'); // -> true +console.log(!!''); // -> false 空字符串 +console.log(!!0); // -> false 数字 0 +console.log(!!10); // -> true +console.log(!!null); // -> false +console.log(!!undefined); // -> false +console.log(!![].length); // -> false +``` + +### 流程控制、比较、运算符等 + +* 流程控制 + * If: + * Switch: + * For: + * While: +* 比较: +* 运算符: + +基本跟 Java 一样,下面介绍几个 JavaScript 比较常用、特殊的知识点: + +#### == 和 === 的区别 + +JS 是弱类型语言,=== 表示全等判断,会把类型也进行比较: + +```js +2 == '2' // -> true +2 === '2' // -> false +``` + +#### + 运算符会改变数据类型 + +运算符会导致数据类型的改变,这是因为运算符同时表示多种含义导致。+ 运算符既可以链接字符串,也可以计算数字,使用时需要注意: + +```js +2 + 2 // -> 4 number +2 + '2' // -> '22' string +``` + +### ES6 新版语法增强功能 + +ES6 是新一代 JavaScript 语法规范,里面新增了非常多的语法和功能,而且往 Java 等传统语言靠拢。比如 class 类定义、箭头函数、真正的 Set、Map 数据类型等。下面仅列出比较推荐的用法,有一些用法由于不太稳定暂时不推荐使用。 + +##### `...obj` 扩展运算符 + +object 的赋值需要遍历相关字段,比如: + +```js +let bb = { + age: 18, + sex: 'male', +}; +let aa = { + name: '浩睿', +}; +// 在 aa 上面新增 bb 的属性需要 +aa.age = bb.age; +aa.sex = bb.sex; +``` + +这样就比较麻烦,你必须知道所有 key 而且每次新增都需要改动相关字段。为此,ES6 规范将扩展运算符(`...`)引入对象。就上面的例子,可以这样写: + +```js +let bb = { + age: 18, + sex: 'male', + name: '后面的同 key 内容会覆盖前面的' +}; +let aa = { + name: '浩睿', + ...bb, +}; +``` + +相当于把某个对象拆开分别赋值,遇到同样的 key 后面内容会覆盖前面的。详情请看: \ No newline at end of file diff --git a/docs/basis/intro-react.md b/docs/basis/intro-react.md new file mode 100644 index 0000000000..1e0b91bce6 --- /dev/null +++ b/docs/basis/intro-react.md @@ -0,0 +1,198 @@ +--- +title: React 基础知识和介绍 +order: 5 +category: 入门指引 +--- + +> React 是 21 世纪人类智慧的结晶。 + +目前几乎绝大部分的组件化方案都是基于 React 实现,因为 React 就是专门为组件化而生的。因此,ICE 后台解决方案也采用了 React 这套方案进行构建。 + +## 了解 React + +本文档不只谈 React 的功能、特性、优势,而是按照实际业务需求对创建一个 React 组件流程做一个介绍,并附带介绍相关特性给出详细参考文档链接。 + +### 创建一个 React 组件 + +首先拿到一系列的页面,我们第一步并不是去马上开发,而是先观察可复用部分抽出成独立的小组件,然后就可以通过拼接组件组装页面了。 + +制作一个组件通常需要展示一段 HTML 代码,创建一个最简单的 React 方法如下: + +```jsx +class HelloMessage extends React.Component { + + render() { + + return ( +
Hello world!
+ ); + } +} +``` +只需要声明一个继承 React Component 的 class 即可创建一个组件,每个组件必须要有一个 render 方法,render 方法的返回值是一段 JSX 代码。 + +JSX 语法跟 HTML 很像,但是还是有一些不同,比较简单的场景下,你可以看做是一样的。[JSX 具体语法请参见这篇文档](https://facebook.github.io/react/docs/jsx-in-depth-zh-CN.html)。 + +创建了一个 class 我们还需要去实例化、执行才可以渲染到页面上,所以我们可以调用下面这句代码将这个组件实际的渲染出来: + +``` +ReactDOM.render(, document.body); +``` + +### 为 React 组件传入数据 + +组件往往是需要展示一些动态数据的,而不是静态的,因此内容不能写死需要获取并传递下去。为此 React 创建了 props 这个概念用来往组件传入数据。 + +```jsx +class HelloMessage extends React.Component { + render() { + return ( +
Hello {this.props.name}
+ ); + } +} + +ReactDOM.render(, mountNode); +``` +渲染组件的时候,按照 HTML 的方式传递一个属性 name 和值 '浩睿',即可在组件内部的任何位置使用 `this.props.name` 拿到这个值进行处理。 + +props 是只读的,用来获取上层组件传递下来的数据。详情请参见:http://stackoverflow.com/questions/27991366/what-is-the-difference-between-state-and-props-in-react + +### React 组件的变化是基于状态的 + +如果设计一个灯开关组件,那么对于这个开关组件它有两种状态,一种是开关开启状态(此时需要连通电线),一种是开关关闭状态(此时需要断开电线),而摁下开关是则是一种触发行为。为此 React 创建了 state 这个概念用来描述组件内部的状态,并支持获取事件进行触发。 + +```jsx +class Switch extends React.Component { + state = { + // 开关状态默认关闭 + switchStatus: false + } + + switch = () => { + // 切换开关的值 + this.setState({ + switchStatus: !this.state.switchStatus + }); + }; + + render() { + + if (this.state.switchStatus) { + return ( +
+

灯已经打开,电线接通

+ +
+ ); + } else { + return ( +
+

灯已经关闭,电线断开

+ +
+ ); + } + } +} +``` + +> Demo 链接:http://ice.alibaba-inc.com/playground/142 + +组件内用到的数据都算作一种状态,存储在 state 里面,当可以拦截某些行为来去改变 state 的值(比如 点击 按钮),需要注意的是改变当前组件的 state 不能直接用 `this.state.switchStatus = true` 来改,必须使用 `this.setState` 方法进行修改。原因是因为状态改变了之后,React 需要重新执行 render 方法进行渲染,此时 render 方法读取 `this.state.switchStatus` 的值就是最新的数据,渲染结果也是最新的。所以必须有一种机制通知 React state 已经变换了,直接改变 `this.state.switchStatus = true` 的值,React 无法检测到状态有変更,因此必须使用 `this.setState({xxx})` 来修改 state 值。 + +React 组件在渲染的时候需要遵循一定的执行顺序,比如 state 改变之后必须重新执行 render 方法等。为了方便控制 React 的执行顺序和流程,React 创建了生命周期的概念用来处理此类功能。 + +关于 props 和 state 的详解,请参见:http://stackoverflow.com/questions/27991366/what-is-the-difference-between-state-and-props-in-react + +### React 组件的生命周期 + +就像一个人一样,出生、赋予属性(props)、成长(state 変更)、衰老死亡(组件销毁),React 组件同样存在这些状态,便于做相关功能处理。 + +```jsx +class Person extends React.Component { + + // 即将出生(刚开始调用) + componentWillMount() { + console.log('我要出生了,我的名字叫 ', this.props.name); + } + + // 出生(开始渲染,准备初始数据,调用 render 方法) + constructor(props) { + super(props); + + console.log('name', this.props.name); + + this.state = { + name: this.props.name, + age: 0 + }; + + // 时间开始转动,5 秒等于 1 岁 + this.timer = setInterval(() => { + this.setState({ + age: this.state.age + 1 + }); + }, 5000); + + console.log('我正在出生'); + } + + + // 出生完毕(调用 render 完成并渲染到页面上) + componentDidMount() { + console.log('我已经出生'); + } + + // 接收了新的属性 + componentWillReceiveProps(nextProps) { + // 换了个新名字,固定的属性 + if (nextProps.name !== this.state.name) { + console.log('我换了个名字:', nextProps.name); + this.setState({ + name: nextProps.name + }); + } + } + + // 要重新渲染了(准备过生日) + componentWillUpdate() { + console.log('我要改变了!'); + } + // 更新渲染完成了(过完生日) + componentDidUpdate() { + console.log('我改变完了!'); + } + + // 要火化了(组件销毁) + componentWillUnmount() { + // 停止时间 + console.log('再见啦!'); + clearInterval(this.timer); + } + + render() { + console.log('我正在改变!'); + return ( +
+

姓名:{this.state.name},年龄:{this.state.age}

+
+ ); + } +} +``` + +> Demo 链接:http://ice.alibaba-inc.com/playground/143 + +每一次 props 或者 state 改变,都会重新渲染组件,为了阻止渲染,React 还提供了 `shouldComponentUpdate` 方法,在 render 前判断是否有必要执行 render 提升性能。关于 React 声明周期,详情请参见官方文档:https://facebook.github.io/react/docs/react-component.html 。 + +附生命周期图: + +![lifecycle](https://img.alicdn.com/tps/TB1Ng7_MpXXXXamXFXXXXXXXXXX-2850-2945.jpg) + +## 总结 + +至此,几大 React 特性你大概了解了,再来回顾一下: + +* props 用来传递数据,state 用来存储组件内部的状态和数据。props 是只读的,state 当前组件 state 的值可以作为 props 传递给下层组件。 +* React 组件按照生命周期运行,改变 state 就会重新执行 render 方法。render 方法返回的是一段 JSX 语法的结构用来渲染到页面上。 diff --git a/docs/basis/sdk.md b/docs/basis/sdk.md new file mode 100644 index 0000000000..ee9ae65fe5 --- /dev/null +++ b/docs/basis/sdk.md @@ -0,0 +1,39 @@ +--- +title: SDK 命令详解 +order: 2 +category: 入门指引 +--- + +ICE SDK 指的是 `ice-scripts` 这个 npm 包,如果你不希望使用 Iceworks,它提供了终端中零配置的开发体验。接下来我们来了解下 ICE SDK 有哪些命令。 + +## 启动开发模式 + +执行如下命令即可进入开发模式 + +```bash +npm start +``` + +对应的 ICE 命令是 `ice dev`,SDK 会启动一个本地的 HTTP Server,你可以根据终端中的信息打开对应的页面进行前端的开发调试。 + +**可选参数** + +* `-p`, `--port` 指定本地服务端口 +* `-h`, `--host` 指定本地服务绑定主机 +* `-s`, `--skip-install` 跳过依赖安装 +* `--help` 查看帮助信息 + +## 打包编译 + +执行如下命令即可进行项目的编译,编译产生的文件默认会生成在项目目录下的 `build` 目录内。 + +```bash +npm run build +``` + +对应的 ICE 命令是 `ice build`,在编译完成后您可以将这些编译产物托管到 OSS 或 CDN 上。 + +**可选参数** + +* `--debug` 使用 debug 模式不会进行代码的压缩,方便定位问题 +* `-h`, `--help` 查看帮助信息 diff --git a/docs/basis/use-component.md b/docs/basis/use-component.md new file mode 100644 index 0000000000..77d52c8119 --- /dev/null +++ b/docs/basis/use-component.md @@ -0,0 +1,53 @@ +--- +title: 如何使用 ICE 组件 +category: 入门指引 +order: 6 +--- + +ICE 的组件统一使用 NPM 进行管理,所有的组件包都可以通过 npm 命令来安装。 + +## 检索组件 + +ICE 所有组件文档说明都部署在 上,同时你也可以在全局搜索框输入你想要的的组件名称进行查找。 + +## 安装与更新 + +ICE 基础组件在初始化项目时,已默认安装。这里主要讲解业务组件的安装与更新方法。 + +### 安装业务组件 + +在对应的业务组件文档上都有具体的安装和升级方法: + +#### 安装命令: + +```bash +npm install --save +``` + +#### 更新命令: + +```bash +npm install @latest --save +``` + +当需要更新项目内的组件的时,使用此命令 `@latest` 表示当装当前最新版本。也就达到升级组件的目的。 + +> 关于组件版本说明详见 + +## 使用组件 + +使用 `import from '';` 语句载入脚本,并定义为 `ComponentName` 。 + +> 对应组件文档下都有 DEMO 示例,可点击 查看源码 / 实时编辑 查看效果。 + +如: + +```jsx +import ReactDOM from 'react-dom'; +import IceTitle from '@icedesign/title'; + +// .... 省略其他代码 + +// 渲染 +ReactDOM.render(, mountNode) +``` diff --git a/docs/ice-design.md b/docs/ice-design.md new file mode 100644 index 0000000000..1889a1d20d --- /dev/null +++ b/docs/ice-design.md @@ -0,0 +1,93 @@ +--- +title: ICE 设计语言 +order: 2 +cover: https://gw.alicdn.com/tfs/TB1fcX1bkyWBuNjy0FpXXassXXa-1600-422.png +--- + +在淘宝内部,经过长时间调研和沉淀,我们产出了 ICE Design 这一套适合于中后台前端应用使用的设计语言。 +我们基于 ICE Design 开发了大量的可复用代码片段(区块),根据区块进行代码复用,大大节省开发时间,详情请见 [物料 - 区块](#/blocks)。 +脚手架初始模板简称为模板,我们针对实际场景的调研,提供了一批官方精选模板,实际效果请参见 [物料 - 模板](#/scaffolds)。在 [Iceworks](#/iceworks) 中生成项目选择对应脚手架即可。 + +## 升级背景 + +目前传统平台界面的设计语言存在着一些不足,比如色彩单一,大量线条的使用,分割化明显。其实,将这些不足归类一下就是界面单调,雷同性明显,缺少惊喜。也许新的平台类视觉风格可以打破这些束缚,尝试一些新的探索,启发传统的设计认知。因此,结合当下设计趋势,构思了一套新的平台产品设计语言。 + +### IDS 设计语言 + +![IDS 设计语言](https://gw.alicdn.com/tfs/TB1hT1ja1uSBuNjy1XcXXcYjFXa-2762-1040.png) + +### 设计手法 + +![设计手法](https://gw.alicdn.com/tfs/TB1TDWja1uSBuNjy1XcXXcYjFXa-2526-454.png) + +## 介绍 Introduction + +目前大部分的组件体系设计风格任然大同小异,ICE 为了突破现有的设计,尝试采用更激进的设计风格,比如沉浸式的导航设计,无分割的表格设计。新的设计语言除了遵循经典的设计定则,还汲取的最新的设计趋势,比如模块化投影化的处理方式,圆角的处理,更加突出内容的表现方式。 + +## 风格 Style + +### 色彩 + +色彩上相对于其他的组件风格,会将色彩更多的采用到组件和页面当中,避免传统的乏味、沉闷、冰冷的感觉。在合适的节点透出惊喜的感觉。此外增加了渐变的颜色,添加了质感,同时迎合当下流行的趋势。 + +![色彩](https://gw.alicdn.com/tfs/TB12IH9a_tYBeNjy1XdXXXXyVXa-2732-1900.png) + +同时提供了浅色版本和深色版本两个风格主题,在对氛围感有很强的要求的产品中可以尝试深色的主题。 + +![风格主题](https://gw.alicdn.com/tfs/TB1wUylaY9YBuNjy0FgXXcxcXXa-2328-824.png) + +### 字体排版 + +同时使用过多的字体尺寸和样式可以很轻易的毁掉布局。在字体的选择上,采用的是基础的并且适于阅读的字体字号,12、14、16、18、24 号字,并且他们能够良好的适应布局结构。这些尺寸和样式在经典应用场合中让内容密度和阅读舒适度取得平衡。 + +![字体](https://gw.alicdn.com/tfs/TB1hIH9a_tYBeNjy1XdXXXXyVXa-1490-1532.png) + +### 图像 + +在后台界面设计中,图像的用途几乎被忽视,然而图像有着建立情感联系,给人轻松愉悦感的作用。这些是 ICE 新的视觉风格里面需要的,因此,新的设计里加大了图像的透出比例。希望可以给用户更轻松的体验。 + +![图像](https://gw.alicdn.com/tfs/TB1NO09a3mTBuNjy1XbXXaMrVXa-2724-1970.jpg) + +## 基础设计原则 + +**接近原则** + +这样可以给用户一个直观的提示,越靠近的信息区块,关联性越大。接近原则是把信息按一定逻辑进行的“组队”。 + +**层次对比** + +页面上的信息通过组队后,一定会需要有侧重点,这时候对比的方法可以拉开内容之间的差距,从而凸显出页面的重点信息。层次对比是增加视觉效果的最直接的方式。 + +**对齐原则** + +如果页面上一些项是对齐的,就可以得到一个更内聚的单一,像是有一条看不见的线把信息排列的更整齐,即使元素可能在空间上间隔的很远,或不在一个“组队”里,对齐可以告诉用户他们之间还是存在某种联系。 + +**流程顺畅** + +中后台项目用户主要是进行信息查询或完成任务,所以相比前台项目注重页面的点击,在后台项目中路径顺畅要比点击次数更重要,甚至需要用越少的有效点击完成页面任务。流程顺畅可以快速提升用户对页面的好感度。 + +**简化认知** + +为了让用户准确有效的获取到页面的信息,就需要减少对信息元素的误解,简化认知成本,尽量让页面信息直白展现。中后台并不需要太多的“内涵丰富”的概念来呈现内容,准确表述功能减少认知负担。 + +## 预览效果图 + +### 首页预览效果 + +![](https://img.alicdn.com/tfs/TB1bPH0eiqAXuNjy1XdXXaYcVXa-1680-2502.jpg) + +### 表格 + +![](https://img.alicdn.com/tfs/TB1X6H0eiqAXuNjy1XdXXaYcVXa-1680-1953.jpg) + +### 列表页 + +![](https://img.alicdn.com/tfs/TB136D0eiqAXuNjy1XdXXaYcVXa-1680-1683.jpg) + +### Dashboard 页 + +![](https://img.alicdn.com/tfs/TB1U6D0eiqAXuNjy1XdXXaYcVXa-1680-2179.jpg) + +### 氛围增强版 + +![](https://img.alicdn.com/tfs/TB1b0yKgLDH8KJjy1XcXXcpdXXa-1680-1953.jpg) diff --git a/docs/iceworks.md b/docs/iceworks.md new file mode 100644 index 0000000000..012c5efc2e --- /dev/null +++ b/docs/iceworks.md @@ -0,0 +1,136 @@ +--- +title: Iceworks 快速开始 +order: 3 +--- + +**零环境搭建** **零配置** **简单易用** + +Iceworks 是 ICE 推出的辅助开发者快速开发中后台前端应用的 GUI 软件,目前支持 macOS 和 Windows 两大平台。通过 [Iceworks](https://alibaba.github.io/ice/#/iceworks) 点击下载按钮即可。 + +## 创建项目 + +软件启动后,项目目录为空,通过上方的【创建项目】新建一个项目。 + +![undefined | center](https://img.alicdn.com/tfs/TB14o5YlsjI8KJjSsppXXXbyVXa-1648-1128.png) + +选择或新建目录并输入项目信息,点击 创建项目 后,来到创建项目的流程,默认选择 ICE Design 风格的脚手架,公测阶段暂只提供此选择。进入下一步创建目录: + +![undefined | center](https://img.alicdn.com/tfs/TB1hJMUi5qAXuNjy1XdXXaYcVXa-1648-1128.png) + +* 新建一个文件夹或者选择已有的空文件夹(避免覆盖原有文件)。 +* 给项目起一个项目名,以便后续识别。 + +点击创建项目即可完成创建。 + +## 管理项目 + +项目创建完成后,会自动添加到项目列表中,未来开发的项目都会在列表中展示。通过项目管理面板,可执行 **构建** **启动调试** **新建页面** 等操作。 + +![undefined | center](https://img.alicdn.com/tfs/TB1o0rOksLJ8KJjy0FnXXcFDpXa-1424-1184.png) + +## 启动调试服务 + +点击 `启动调试服务` 等待完成后出现服务地址,点击可以预览当前项目。 + +![undefined | center](https://img.alicdn.com/tfs/TB1tsaHksrI8KJjy0FhXXbfnpXa-2586-1398.png) + +初始化的项目默认没有页面,只有基础的框架,接下来可以通过 新建页面 来丰富我们的项目。 + +## 新建页面 + +启动调试服务后,可使用新建页面来搭建页面,通过 [block](https://alibaba.github.io/ice/#/template/block) 的组合完成页面的创建。 + +![undefined | center](https://img.alicdn.com/tfs/TB1uiuIkC_I8KJjy0FoXXaFnVXa-1424-1184.png) + +进入 block 搭建页面 + +![undefined | center](https://img.alicdn.com/tfs/TB1boqPlsrI8KJjy0FhXXbfnpXa-1704-1184.png) + +上方列出了当前项目可用的 layout 布局方式,选中任一一个作为新页面的布局。 + +左侧列出了当前选择的 blocks, 点击即可选择该 block 搭建页面。右侧为选中 block 组合的缩略图预览。 + +选择 layout 以及 block 后,点击右下角生成页面,会提示输入页面名,路由名,可以定义需要的名称, + +* 页面名:表示生成的文件名称。 +* 路由名:表示页面的访问地址,可通过 `http://127.0.0.1:4444/#/xxxx` 访问到对应的路由页面。 + +示例中,创建了 `page2` 访问后即可看到刚搭建的页面了。 + +![undefined | center](https://img.alicdn.com/tfs/TB15mjklv6H8KJjy0FjXXaXepXa-1704-1184.png) + +## 进入开发调试 + +点击项目版面上的 `编辑中打开` 会立即使用设置中选择的编辑器打开项目,目前支持 [Visual Stadio Code](https://code.visualstudio.com/),[Sublime Text 3](https://www.sublimetext.com/),`WebStorm` 和 `Atom` 等编辑器,推荐使用 [Visual Stadio Code](https://code.visualstudio.com/),如果你的电脑中未安装请先安装。 + +项目目录结构说明: + +``` +project-name +├── dist // 打包资源 +├── mock // 模拟数据 +├── public // 静态资源 +├── src +│ ├── components // 公共组件 +│ ├── config // 公共配置 +│ ├── layouts // 通用布局 +│ ├── pages // 页面 +│ ├── utils // 通用方法 +│ ├── global.scss // 全局样式 +│ ├── index.html // 入口模板 +│ ├── index.js // 应用入口 +│ └── routes.jsx // 路由入口 +├── tests // 测试 +├── .editorconfig // 代码风格配置 +├── .eslintignore // eslint 忽略目录配置 +├── .eslintrc // eslint 配置 +├── generator.json // generator.json +├── package.json // package.json +├── README.md // 项目说明 +└── yarn.lock // 模板版本管理 +``` + +例如上一步已创建的 `Page3` 页面: + +![undefined | center](https://img.alicdn.com/tfs/TB1E912kwvD8KJjy0FlXXagBFXa-1810-1126.png) + +通过二次开发增加业务逻辑,完成业务需求。 + +## 打包发布 + +点击项目面板上的构建项目按钮,将开发的构建出最终的 js css 等资源。 + +构建完成后,会在项目目录下生成 `build` 文件夹,里面存在了 `index.js` `index.css` 文件。使用你熟悉的方式,上传到对应的 cdn 服务器。 + +![undefined | center](https://img.alicdn.com/tfs/TB1hCjMlx6I8KJjy0FgXXXXzVXa-1082-814.png) + +## 部署上线 + +上线过程即发布 HTML 文件的过程,`index.html` 文件存在在 `public` 目录中,将 `index.html` 文件复制到对应的服务服务器,并修改 html 源码中的 `/build/index.css` 和 `/build/index.js` 地址,是上一步中得到的 cdn 地址以及站点标题。 + +一个标准的 HTML 文件如下所示: + +```html + + + + + + + + + {站点标题} + + + +
+ + + + + +``` + +> 在线上环境我们强烈推荐使用 production 版本的 React,而不是 development 版本。它们之间的区别除了体积之外,还包括一些针对线上环境的性能优化。 + +到这里你已经学会使用 Iceworks 创建一个项目并发布:) diff --git a/docs/others/qa.md b/docs/others/qa.md new file mode 100644 index 0000000000..0eca344041 --- /dev/null +++ b/docs/others/qa.md @@ -0,0 +1,72 @@ +--- +title: 常见问题 QA +category: 其它 +order: 1 +--- + +> 持续更新中... +> 如有问题可以到 反馈 + +## ICE 的浏览器兼容策略是什么 + +由于 ICE 优先使用 React 16+,其需要的最低 IE 版本为 11,如果您需要在以下的版本使用,您可能需要引入一些 polyfill 来支持 `Map`, `Set` 等特性。参考[React 官网说明](https://reactjs.org/blog/2017/09/26/react-v16.0.html#javascript-environment-requirements)。 + +以下代码可以帮助你在低版本 IE 下自动跳转到我们提供的提示浏览器升级页面。当然您也可以使用自定义的浏览器升级页面。 + +``` + +``` + +添加如上代码后,如果使用 IE11 及以下浏览器访问页面,则会自动跳转到统一引导升级浏览器的页面。 + +## WebStorm/IDEA 编辑器卡顿现象 + +由于项目在安装依赖后,产生文件夹 `node_modules` 含有较多的碎小文件,编辑器在索引文件引起的卡顿。 +IDEA 尤为明显,可通过 exclude `node_modules` 目录,不需要检索该文件夹下的内容。 + +## 如何设置网页在浏览器 Tab 上面的 Icon (favicon) + +细心的同学可能会看到页面在浏览器 Tab 上面会有自定义的 Icon: + +![](//img.alicdn.com/tfs/TB1ct6bPpXXXXXYXFXXXXXXXXXX-484-82.png) + +如果你想要在自己站点上面加上这个 Icon 可以按照如下步骤添加: + +1. 准备一个 Icon,文件格式可以为 `.png` 或者 `.ico`,正方形,分辨率可以是 32x32px 或者 64x64px 文件体积要求尽可能小。 +2. 上传 CDN 拿到一个 url 或者在自己服务器配置静态资源服务 +3. 在 HTML 页面 `` 标签里面添加如下代码:`` + ![](//img.alicdn.com/tfs/TB1IC53PpXXXXbmXVXXXXXXXXXX-1834-774.png) + +这样就添加成功啦! + +## 如何在页面显示原始的 HTML 内容 + +出于安全方面的考虑,React 默认会将节点中 html 代码进行转义,比如: + +```jsx +class Demo extends Component { + render() { + const content = 'hello world'; + return
{content}
; + } +} + +// 输出 hello world +``` + +如上,`` 标签并不会在页面上被解析,而是被当成字符串输出了。React 提供了 `dangerouslySetInnerHTML` 属性帮助我们进行类似 `innerHTML` 的操作: + +```jsx +class Demo extends Component { + render() { + const content = 'hello world'; + return
; + } +} + +// 输出 hello world +``` + +更多内容请参考 [Dangerously Set innerHTML](https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml) diff --git a/package.json b/package.json index ce4c51b1c9..394a58d7dc 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,10 @@ "publish": "git fetch --all && git pull origin master && lerna publish", "bootstrap": "lerna bootstrap", "setup": "lerna setup", - "db": "node ./scripts/generate-marterials-database", + "db": "node ./scripts/generate-marterials-database && node ./scripts/generate-docs-database", "lint": "npm run lint:nofix -- --fix", "lint:nofix": "eslint --cache --ext .js --ext .jsx ./", - "format": - "prettier blocks/*/src/**/*.js blocks/*/src/**/*.jsx layouts/*/src/**/*.js layouts/*/src/**/*.jsx scaffolds/*/src/**/*.js scaffolds/*/src/**/*.jsx tools/**/*.js --write" + "format": "prettier blocks/*/src/**/*.js blocks/*/src/**/*.jsx layouts/*/src/**/*.js layouts/*/src/**/*.jsx scaffolds/*/src/**/*.js scaffolds/*/src/**/*.jsx tools/**/*.js --write" }, "repository": { "type": "git", @@ -33,8 +32,8 @@ "ghooks": "^2.0.2", "ice-scripts": "^0.1.0", "lerna": "^2.5.1", + "mark-twain": "^2.0.2", "moment": "^2.20.1", - "prettier": "^1.10.2", "request": "^2.83.0", "request-promise": "^4.2.2", "semver-regex": "^1.0.0", diff --git a/scripts/generate-docs-database.js b/scripts/generate-docs-database.js new file mode 100755 index 0000000000..50f389c484 --- /dev/null +++ b/scripts/generate-docs-database.js @@ -0,0 +1,68 @@ +const fs = require('fs'); +const mkdirp = require('mkdirp'); +const path = require('path'); +const glob = require('glob'); +const markTwain = require('mark-twain'); + +const destDir = path.join(__dirname, '../databases'); +const dest = path.join(destDir, 'docs.db.json'); +const sourceDir = path.join(__dirname, '../docs'); + +glob( + '**/*.md', + { + nodir: true, + ignore: 'README.md', + cwd: sourceDir, + }, + (err, files) => { + if (err) { + throw err; + } + + const result = []; + + files.forEach((file) => { + const content = fs.readFileSync(path.join(sourceDir, file), 'utf-8'); + + const jsonML = markTwain(content); + + // 隐藏文档过滤 + if (jsonML.meta.hide) { + return; + } + + if (!jsonML.meta.title) { + throw new Error(`${file} 缺失标题, 请补充`); + } + + const sourceData = { + filename: file, + path: file.replace(/\.md$/, ''), + ...jsonML.meta, + + jsonml: jsonML.content, + }; + result.push(sourceData); + }); + + fs.writeFileSync(dest, JSON.stringify(result, null, 2), 'utf-8'); + console.log('文档数据生成完毕. Docs DB Generated.'); + console.log(dest); + } +); + +/** + * 从 jsonml 结构中获取纯字符串 + */ +function getJsonmlString(jsonml) { + let result = ''; + for (let i = 1; i < jsonml.length; i++) { + if (Array.isArray(jsonml[i])) { + result += getJsonmlString(jsonml[i]); + } else if (typeof jsonml[i] === 'string') { + result += jsonml[i] + ' '; + } + } + return result; +} diff --git a/scripts/generate-marterials-database.js b/scripts/generate-marterials-database.js index 9268a2f0be..4e843cfcc8 100755 --- a/scripts/generate-marterials-database.js +++ b/scripts/generate-marterials-database.js @@ -190,22 +190,22 @@ function main() { .then(([blocks, layouts, scaffolds]) => { const distDir = path.resolve(__dirname, '../databases'); mkdirp.sync(distDir); - fs.writeFileSync( - path.join(distDir, 'blocks.db.json'), - JSON.stringify(blocks, null, 2) + '\n' - ); + const blocksDest = path.join(distDir, 'blocks.db.json'); + const layoutsDest = path.join(distDir, 'layouts.db.json'); + const scaffoldsDest = path.join(distDir, 'scaffolds.db.json'); + fs.writeFileSync(blocksDest, JSON.stringify(blocks, null, 2) + '\n'); - fs.writeFileSync( - path.join(distDir, 'layouts.db.json'), - JSON.stringify(layouts, null, 2) + '\n' - ); + fs.writeFileSync(layoutsDest, JSON.stringify(layouts, null, 2) + '\n'); fs.writeFileSync( - path.join(distDir, 'scaffolds.db.json'), + scaffoldsDest, JSON.stringify(scaffolds, null, 2) + '\n' ); - console.log('Database generated.'); + console.log('物料数据生成完毕. Marterials DB Generated.'); + console.log(blocksDest); + console.log(layoutsDest); + console.log(scaffoldsDest); }) .catch((err) => { console.log('caught error:\n', err.message);