Welcome to 前端教程’s documentation!¶
Html 基础¶
Html介绍¶
html 本质是一个 XML 文档。
最简单的 html 可以是一个 text 文档,这时,所有文字都是在一行的,当需要对某些文字加上特效时, 可以使用 XML 标签包围那段文字。标准一点的 html , 每段文字都需要包含在 XML 标签中。
如果希望尝试下面的例子,可以新建一个 txt 文件,修改后缀名为 .html
.
写入下面的html内容, 右键使用 chrome、firefox 等浏览器打开。就能预览效果。
最简单的HTML
这是一行, 这也在同一行渲染为html如下
这是一行, 这也在同一行
html基础元素¶
段落 paragraph
<p>这是一个段落</p> <p>这是另一个段落</p>这是一个段落
这是另一个段落
标题 header
标题分为很多种,有一级标题、二级标题……六级标题, 对应的分别是 h1/h2/h3…h6 标签, 一级标题最大,后面的一次减小。
<h1>一级标题</h1> <h2>二级标题</h2> <h3>三级标题</h3> <h4>四级标题</h4> <h5>五级标题</h5> <h6>六级标题</h6>渲染为html如下
一级标题
二级标题
三级标题
四级标题
五级标题
六级标题
有序列表 ordered list
列表稍微复杂一些,需要使用两个标签。 渲染出来后是一个带有序号的列表。
- ol 表示有序列表
- li 表示每一项。 (list)
<ol> <li>这是第一项</li> <li>这是第二项</li> <li>这是第三项</li> </ol>渲染为html如下
- 这是第一项
- 这是第二项
- 这是第三项
无序列表 unordered list
和有序列表类似,但是使用 ul 标签。 渲染出来后是一个不带序号的列表。
<ul> <li>这是第一项</li> <li>这是第二项</li> <li>这是第三项</li> </ul>渲染为html如下
- 这是第一项
- 这是第二项
- 这是第三项
表格
表格更复杂一些,使用了四种标签。
- table: 表示一个表格
- tr: 表示表格的一行
- td: 表示一个单元格
- th: 和td类似,表示一个表头单元格
<table> <tr> <th>姓名</th> <th>年龄</th> </tr> <tr> <td>张三</td> <td>21</td> </tr> <tr> <td>李四</td> <td>22</td> </tr> </table>渲染为html如下
姓名 年龄 张三 21 李四 22
图片 - image
将图片链接贴到网页。
<img src="//www.baidu.com/img/bd_logo1.png" />渲染为html如下
交互控件 - input
交互控件都是 input, 通过type字段指定其类型。
其实还有check, 就不介绍了。
<input type="password" placeholder="密码输入框"/> <input placeholder="普通输入框"/> <br /> <input type="button" value="这是一个按钮" />渲染为html如下
div
div 可谓是前端开发中最广泛使用的标签。
div 本身的表现形式是换行, 和 p 差不多。但是可以通过各种css添加样式表现出各种形态。 如果需要调整某一块的样式,一般都先通过 div 包一层,然后在上面加 样式。
<div>这是一个div</div> <div>这是第二个div</div>渲染为html如下
这是一个div这是第二个div
span
span 也比较常用,和 div 差不多。和 div 的区别在于,其默认情况下不会换行。
<span>这是一个span</span> <span>这是第二个span</span>渲染为html如下
这是一个span 这是第二个span
Html控件属性¶
在上面的例子中,img 元素就拥有 src 属性, input元素也拥有 type 属性.
<img src="//www.baidu.com/img/bd_logo1.png" />
<input type="button">这是一个按钮</input>
html 控件属性直接写在标签里面。
有一些比较常用的属性。
id
id 用来唯一标示一个元素, 即命名,一个页面不允许两个元素id相同 (其实也不是强制的,如果一样的话,会出现一些问题。)。
任何元素都可以有id。
<img id="my-image" src="//www.baidu.com/img/bd_logo1.png" />
class
class 和 id 类似,也是一个名字,但是可以重复,而且鼓励重复, 用来标示同一类的一组控件。比如居右的一组控件可能有一组相同的class。 对于样式复用很有帮助。
一个控件可以有多个 class,通过空格隔开。
<input class="myinput hisinput" type="button">这是一个按钮</input> <input class="myinput" type="button">这是另一个按钮</input>
rowspan/colspan
table 专用,用来制作跨行跨列的表格。不多介绍。
style
用来定义内联css样式,后面会说。不做介绍。
html/head/body¶
一般不会直接在一个文件中写 html 元素,而是有一个骨架,主要分为 head/body.
html骨架如下
<html>
<head>
<title>这是一个测试页面</title>
</head>
<body>
<div>这是页面正文内容</div>
</body>
</html>
title 中的内容会显示在浏览器中的标签tab上。
body 中写 html 内容。
CSS 基础¶
如果急于求成,建议直接看 react 部分,这部分可以以后再看。
概念¶
css 颜色
颜色有
- 命名表示法: red, 通过颜色名称表示颜色,这种方法表示的颜色数量有限。
- 16进制表示: #ff0000, 每两位表示一个颜色的值,分别是 rbg三种颜色的比例。
- rgb格式: rgb(255, 0, 0), 三位分别表示 rgb 的颜色比例,范围 0-255.
- hls格式: 不常用,不做介绍。
以上三种颜色都是 三个变量,但是都可以选择性地加上第四个变量,表示透明度,也不做介绍。
大小单位
大小通常使用像素为单位: px. 如宽、高、字体。也可以使用百分比: 50%, 或者以字符数为单位: em 。
使用css
css最简单的使用方法就是通过 style 内联
<div style="color: red">这段文字是红色</div>
常用css¶
要看所有css,到 http://www.w3school.com.cn/cssref/index.asp 快速预览, 或者点击去查看。
或者到 http://www.w3school.com.cn/css/index.asp 系统地学习。
比较常用的css:
- margin: 外边距
- padding: 内边距
- color: 颜色
- border: 边框
- width/height: 宽高
- font: 字体
- background: 背景
案例:
<div style="width: 150px;height: 50px; background: red">这是一个框</div>
渲染如下
与 HTML 结合¶
一般来说,直接将css样式通过 style 属性内联到html中,作用有限。 因为需要针对每一个元素单独写一个样式。 所以就有必要用到CSS选择器。 对元素批量设置样式。
要对元素批量设置样式,需要将CSS放到 <style></style>
标签中。
css选择器¶
选择器常用的有三种
通过 id 选择
这种方式使用
#
开头。<style> #mydiv { width: 150px; height: 50px; background: red; } </style> <div id="mydiv">这是一个框</div>
上面 style 标签也是包含在html中的, 其中 css 样式 首先选定需要修饰的元素,然后在大括号中说明加什么特效。
结果如下
这是一个框通过标签选择,如 p/h1/h2/table 等
这种方式无需使用任何开头字符
<style> div { background: red; } p { background: green; } </style> <div>我是div</div> <p>我是段落</p>
效果如下
我是div我是段落
通过class选择
通过class的选择方式使用
.
开头这是最广泛的选择方式,因为class可以标示一类控件。
<style> .red-div { background: red; } .big-div { font: 25px bolder; } </style> <div class="red-div">我是红色</div> <div class="red-div">我也是红色</div> <div class="big-div">我字很大</div> <div class="red-div big-div">我红色而且字很大</div>
效果如下
我是红色我也是红色我字很大我红色而且字很大选择器的层叠和组合
上面说了三种选择器
- id 选择器
- class 选择器
- tab 选择器
另外html文档是 xml 文档,其中的元素是一层一层嵌套的。所以存在选择器的嵌套。
- #mydiv .red-div :选择id为mydiv元素下面的所有 class=red-div 的下层元素,不必是直接子元素。
- #mydiv>.red-div :和上面差不多,但是必须是直接子元素。
- .red-div, .big-div: 同时选中 class=red-div 和 class=big-div的元素,或的关系。
- .red-div.big-div: 选中 class=red-div 且 class=big-div的元素,且的关系。
- #mydiv .red-div :选择id为mydiv元素并且class=red-div 的元素。
其他选择器
css 选择器有很多种形式,比如状态选择(hover)、孩子选择(nth-child)等。不介绍。
引用css¶
上面介绍了 style 内联和html的 style 标签使用css样式。
更加通用的做法是将css定义在一个 css文件中,html 通过超链接引入.
<link rel="stylesheet" href="/static/mystyle.css" type="text/css">
另外需要知道 css 有很多变种,如 scss,这里也不做介绍。
JavaScript 介绍¶
JavaScript 作用¶
html用来定义文档,css用来添加效果。但是这两个东西终究是静态的,一旦创建就无法修改。为了得到动态页面,有两种方法。
后端渲染
HTML 本质上是给xml格式的字符串,后端先构造出为想要的html字符串,发送给前端。
这种方法在某些情况下代价很高,因为无论html改动多小,都需要后端将 html 完全构造一遍,传回浏览器。
前端渲染
通过在浏览器中嵌入 JavaScript。
JavaScript 是前端编程语言,可以动态生成、修改、删除 xml 元素,也能增加事件、修改元素属性、 修改元素id/class/css。几乎可以完全操控当前的html。
前端编程也就是使用 JavaScript 编程。
下面是一个例子
<html>
<head>
<meta charset="utf-8" />
<title>测试网页</title>
</head>
<body>
<script>
function addOne(){
var newLi = document.createElement('li');
newLi.innerText="一个元素";
var dom = document.getElementById("my-list");
dom.appendChild(newLi)
}
</script>
<div>点击下面的按钮,可以增加列表</div>
<button onClick="addOne()">增加一个</button>
<ol id="my-list"></ol>
</body>
</html>
JavaScript 一些注意点¶
lambda表达式¶
JavaScript 引入和函数式编程的概念,所以介绍一下箭头函数。
function add(a, b) {
return a + b;
}
// 使用箭头定义这个函数。这种方式是等价的。
(a, b) => {
return a + b;
}
// 对于这种只有一个return语句的简单的函数,可以去掉大括号,简化return语句。
(a, b) => a + b
// 简化形式的函数体加上括号可读性更好一点。也能避免一些错误。
(a, b) => (a + b)
// 将这个箭头函数赋值给一个变量
let add = (a, b) => (a + b)
add(1, 2) // 返回 3
this¶
JavaScript 中的this是个很具有迷惑性的东西。
class OtherClass {
do_call(func) {
func()
}
}
class TestClass{
a = 9
myfunc() {
console.log(this.a)
}
wrongCall() {
new OtherClass().do_call(this.myfunc)
}
}
正常情况下调用 TestClass.myfunc
是没有问题的。
一旦将myfunc传递给其他对象调用, 比如调用 TestClass.wrongCall
,就会出现问题, this.a
不存在。
因为函数中 this 所指向的上下文是运行时动态获取的, 当myfunc传递到 OtherClass 后,this指向的就是 OtherClass 了, 不存在 this.a
。
正确的做法是使用 箭头函数,因为箭头函数会保存函数定义时的上下文。
class OtherClass {
do_call(func) {
func()
}
}
class TestClass{
a = 9
myfunc = () => {
console.log(this.a)
}
wrongCall() {
new OtherClass().do_call(this.myfunc)
}
}
Array操作¶
let datas = ["a", "b", "c"]
// 添加元素
datas.push('d')
// 挨个处理
datas.map(item => (item+item)) // 输出: ["aa", "bb", "cc", "dd"]
window/document¶
javascript 中有两个全局对象 - window/document
document
保存当前html的所有元素。可以用于增删改查元素。
window
保存当前浏览器窗口的信息。比如 当前url、浏览器窗口的宽高。
react 基础¶
怎么启动一个React项目¶
外网使用 create-react-app 工具快速创建react项目.
前提
安装nodejs ( https://nodejs.org/zh-cn/ ),
创建react项目
# npm更换为taobao源, 因为资本主义网络太慢 npm config set registry https://registry.npm.taobao.org # 安装 create-react-app 脚手架 npm install -g create-react-app # 使用 create-react-app 快速创建一个 react+typescript 项目 npx create-react-app my-app --typescript # 进入项目,启动 cd my-app; npm start
如果是内网, 下载 antd_template. 直接修改 src/pages/Home/index.tsx
上面的做完后,打开浏览器访问 http://localhost:3000
浏览器中按 F12 调试。
一些概念¶
控件的组合–组件¶
react有一个组件的概念。可以将一大堆 html标签 封装为一个组件,从而做到复用。
组件有两种。
第一种比较简单,直接是一个函数:
function MyComponent() { return <div> <input /> <input type="button"/> </div> }
第二种是一个类,需要实现render方法, 继承 React.Component
。
class MyComponent extends React.Component { function render() { return <div> <input /> <input type="button"/> </div> } }
入口¶
一般来说,一个React页面的初始状态是一个空页面。首先将一个顶层组件塞到html中, 这个顶层组件又调用了很多其他子组件。合在一起看就是嵌套的 xml 。
事件¶
每一个html元素都可以监听事件,比如鼠标点击事件、键盘事件等。比较常用的就是 onClick。 可以注册一个函数到事件上,事件一旦触发,就会执行那个函数
function say_click(){ console.log("do click") } function MyComponent() { return <div onClick={say_click}> <input /> <input type="button"/> </div> }
state¶
React.Component
内部维护了一个 state 状态,是一个字典。使用 this.setState
修改state中的值。
修改后,会自动更新UI界面。 state 可以通过 this.state
读取
props¶
React.Component
可以接受一组参数。这组参数只读,无法修改。
通过 this.props
访问,是一个字典。
完整教程¶
了解上述概念后,按照下面的教程做一遍就知道了。
中文版教程: https://react.docschina.org/tutorial/tutorial.html
装逼版教程: https://reactjs.org/tutorial/tutorial.html
没有比这讲的更详细的。
React 最重要的概念:虚拟dom。有兴趣了解下,不了解也能用。
typescript 介绍¶
typscript 是 JavaScript 的一个变种,是 JavaScript 的超集, 完全向下兼容 JavaScript,并额外提供了静态类型检查。
定义接口(类型)¶
interface TreeType {
id: string;
name: string;
age: number;
}
interface ForestType {
trees: Array<TreeType>
}
function doSomething(tree: TreeType) {
const name = tree.name;
// ... ...
}
上面是定义接口的例子,使用 name: type
的形式说明类型。使用 interface
定义复杂类型。
定义Component¶
定义 component 和原始 JavaScript 区别在于需要加上 props 的定义。
import * as React from 'react';
import * as ReactDom from 'react-dom';
interface MyProps {
title: string;
items: Array<string>;
}
clsss MyComponent extends React.Component<MyProps, {}> {
render() {
return <div>
<div>{this.props.title}</div>
<ul>
{this.props.items.map(item=>(<li>{item}</li>))}
</ul>
</div>
}
}
ReactDom.render(
<MyComponent title="all items" items={['item1', 'item2']}/>,
document.getElementById('root')
)
typescript的类型¶
类型 | 说明 |
---|---|
boolean | bool型 |
number | 数字类型,如整数、浮点 |
string | 字符串 |
Array<TYPE> | 定义数组类型,如 字符串数组 Array<string> |
TYPE[] | 同 Array , 如 string[] |
[TYPE1, TYPE2, ……] | 定义元组,如 let x: [string, number] |
enum | 定义枚举,如 enum Color {Red, Green, Blue} |
any | 任意类型,如果不给变量定义类型,默认是Any |
void | 和any相反,表示没有任何类型,通常作为函数返回值。 |
null/undefined | 就是 null 和 undefined 本身 |
never | 表示永远不存在的类型,如 死循环函数的返回值。 |
object | 对象类型,即非原始类型(number/string/boolean …)的其他类型。。 |
另外有两种类型转换的方法:
- let two = (<string>one)
- let two = (one as string)
route 路由¶
如果只会用 React 写个单页面应用,没有任何跳转,也算不得什么英雄好汉。
基本原理¶
JavaScript中通过 window.location 可以访问当前页面的 url 。
假设我们现在有三个页面
- TreeList: 显示植物列表
- TreeDetail: 显示植物详情
- Home: 主页
为了在 React 中根据不同的url显示不同内容。可以像下面一样写。
class Index extends React.Component<any, any> {
render() {
if (window.location.pathname == "/treeList") {
return <TreeList />
} else if (window.location.pathname == "/treeDetail") {
return <TreeDetail />
} else {
return <Home />
}
}
}
上面的代码也能工作,不过适用场景有限,社区已经有了更完善的 react-router
。
react router¶
上面的代码改写为 react router 路由代码就是下面的。
import React from 'react'
import { BrowserRouter, Route, Link } from 'react-router'
React.render((
<BrowserRouter>
<Route exact={true} path="/" component={Home} />
<Route path="/treeList" component={TreeDetail} />
<Route path="/treeDetail" component={TreeList} />
</BrowserRouter>
), document.body)
注意 BrowserRouter 只能有一个,放在最外层,下面的 Route 可以有很多个,而且可以嵌套多层。
其中,exact表示url是否完全匹配,默认是前缀匹配,path 表示匹配到什么url,component表示匹配成功后渲染什么组件。
通过 Route 渲染的组件,会具有 this.props.history
和 this.props.match
, 通过 this.props.history.push() 跳转到其他页面
this.props.history.push("/treeList")
具体接口看官方文档: https://reacttraining.com/react-router/web/guides/quick-start
中文教程:
mobx¶
mobx 介绍¶
mobx 是一个数据管理的 js 库。里面实现了观察者模式。
如果照着 React 基础教程写过一遍,可能觉得react的 state/props 比较美好。 实际应用在大型项目中,就不是那么回事了。因为组件嵌套的时候,父组件只能通过 props 传递数据到子组件。 而子组件又不能修改props,就算子组件将其保存为state,修改后,父组件也检测不到子组件做了什么修改, 因为父子组件不能交互。
比如做一个 可以自由展开树形结构,每一层每一个节点都是一个组件,一直递归,每个组件管理自己节点的数据。 当节点想要修改的时候,必须要顶层组件透传下来一个修改的函数,然后由顶层节点修改,再通过props传递到下层节点。
这时候,mobx就派上用场了,mobx可以将一个数据注册为 被观察者 ,然后数据export给所有模块使用。
mobx 使用¶
注册被监视数据¶
一般来说,同一个业务的数据存放到同一个 Store 类里面。通过 @observable
标记为被观察数据。
假设我们要实现统计按钮点击次数的功能,下面的例子注册一个按钮点击次数的被观察数据。然后 export 导出.
// store.ts
import {observable} from 'mobx';
class Store {
@observable
public clickNumber: number = 0;
// 下面还可以继续使用 @observable 注册其他被监视数据。
// ... ...
}
export default new Store();
编写 Action¶
使用 @action
将函数标记为action, 用来修改 store 数据
// action.ts
import {action} from 'mobx';
import store from './store';
class Action {
@action
public increaseClickNumber() {
store.clickNumber += 1;
}
// 如果需要,下面还可以继续写其他 action 函数
// ... ...
}
在react中使用¶
react组件需要使用 @observer
注册为观察者,否则数据改变后组件并不会自动更新。
然后react组件中就可以通过 store 使用数据,通过 action 修改数据了。
import * as React from 'react';
import {observer} from 'mobx-react';
import action from './action';
import store from './store';
@observer
class MyComponent extends React.Component<any, any> {
public render() {
return <div>
你已经点击了{store.clickNumber}次.
<button onClick={()=>action.increaseClickNumber()}>猛击此处</button>
</div>
}
}
请求服务器数据¶
一般 action 中会请求远程服务器得到想要的数据。
介绍一下请求数据的方法 – fetch。
发送get请求¶
fetch('/url') .then(req=>req.json()) .then(data=>{ // do something })
发送post请求¶
let postData = {name: "Jack"} fetch('/url', { method: 'post', body: JSON.stringify(postData), headers: { "Content-Type": "application/json" } }) .then(req=>req.json()) .then(data=>{ // do something })