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

列表稍微复杂一些,需要使用两个标签。 渲染出来后是一个带有序号的列表。

  1. ol 表示有序列表
  2. li 表示每一项。 (list)
<ol>
    <li>这是第一项</li>
    <li>这是第二项</li>
    <li>这是第三项</li>
</ol>

渲染为html如下

  1. 这是第一项
  2. 这是第二项
  3. 这是第三项

无序列表 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 控件属性直接写在标签里面。

有一些比较常用的属性。

  1. id

    id 用来唯一标示一个元素, 即命名,一个页面不允许两个元素id相同 (其实也不是强制的,如果一样的话,会出现一些问题。)。

    任何元素都可以有id。

    <img id="my-image" src="//www.baidu.com/img/bd_logo1.png" />
    
  2. class

    class 和 id 类似,也是一个名字,但是可以重复,而且鼓励重复, 用来标示同一类的一组控件。比如居右的一组控件可能有一组相同的class。 对于样式复用很有帮助。

    一个控件可以有多个 class,通过空格隔开。

    <input class="myinput hisinput" type="button">这是一个按钮</input>
    <input class="myinput" type="button">这是另一个按钮</input>
    
  3. rowspan/colspan

    table 专用,用来制作跨行跨列的表格。不多介绍。

  4. 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 部分,这部分可以以后再看。

概念

  1. css 颜色

    颜色有

    • 命名表示法: red, 通过颜色名称表示颜色,这种方法表示的颜色数量有限。
    • 16进制表示: #ff0000, 每两位表示一个颜色的值,分别是 rbg三种颜色的比例。
    • rgb格式: rgb(255, 0, 0), 三位分别表示 rgb 的颜色比例,范围 0-255.
    • hls格式: 不常用,不做介绍。

    以上三种颜色都是 三个变量,但是都可以选择性地加上第四个变量,表示透明度,也不做介绍。

  2. 大小单位

    大小通常使用像素为单位: px. 如宽、高、字体。也可以使用百分比: 50%, 或者以字符数为单位: em 。

  3. 使用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选择器

选择器常用的有三种

  1. 通过 id 选择

    这种方式使用 # 开头。

    <style>
        #mydiv {
            width: 150px;
            height: 50px;
            background: red;
        }
    </style>
    
    <div id="mydiv">这是一个框</div>
    

    上面 style 标签也是包含在html中的, 其中 css 样式 首先选定需要修饰的元素,然后在大括号中说明加什么特效。

    结果如下

    这是一个框
  2. 通过标签选择,如 p/h1/h2/table 等

    这种方式无需使用任何开头字符

    <style>
        div {
            background: red;
        }
        p {
            background: green;
        }
    </style>
    
    <div>我是div</div>
    <p>我是段落</p>
    

    效果如下

    我是div

    我是段落

  3. 通过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>
    

    效果如下

    我是红色
    我也是红色
    我字很大
    我红色而且字很大
  4. 选择器的层叠和组合

    上面说了三种选择器

    • 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 的元素。
  5. 其他选择器

    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用来添加效果。但是这两个东西终究是静态的,一旦创建就无法修改。为了得到动态页面,有两种方法。

  1. 后端渲染

    HTML 本质上是给xml格式的字符串,后端先构造出为想要的html字符串,发送给前端。

    这种方法在某些情况下代价很高,因为无论html改动多小,都需要后端将 html 完全构造一遍,传回浏览器。

  2. 前端渲染

    通过在浏览器中嵌入 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 …)的其他类型。。

另外有两种类型转换的方法:

  1. let two = (<string>one)
  2. 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.historythis.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 模型

_images/mobx-model.jpg

mobx 实现了观察者模型,一个数据注册为 被监视 后, 可以被 观察者 监视。 被监视数据不能直接修改,只能通过 Action 修改。

总体上数据流是单向的。

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
    })

Indices and tables