SampsonKY


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

封装fetch请求

发表于 2020-03-15 | 分类于 前端学习

封装 fetch 请求

  • 如果只是简单的请求,没必要引入 aixos,通过将fetch请求的相关代码封装在request.js/request.ts文件中,在使用的时候引入相关请求方法即可,好处有几点:
    • 请求的地方代码更少。
    • 公共的错误统一在一个地方添加即可。
    • 请求定制的错误还是请求自己也可以处理。
    • 扩展性好,添加功能只需要改一个地方。
  • 下面给出我在项目中封装的 request.ts 文件具体内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// path:src/utils/request.ts
const request = (url: string, config: any) => {
return fetch(url, config)
.then((res: any) => {
if (!res.ok) {
// 服务器异常返回
throw Error('接口请求异常');
}
return res.json();
})
.catch((error: any) => {
return Promise.reject(error);
});
};

// GET请求
export const get = (url: string) => {
return request(url, { method: 'GET' });
};

// POST请求
export const post = (url: string, data: any) => {
return request(url, {
body: JSON.stringify(data),
headers: {
'content-type': 'application/json',
},
method: 'POST',
});
};
  • 根据功能建立不同的请求模块,如列表模块:
1
2
3
4
5
6
7
8
9
10
11
12
13
// path:src/services/api/list.ts

import * as Fetch from '../../utils/request';

export async function getListData () {
return Fetch.get('URL1');
}

export async function getListItemDetail (id: number) {
return Fetch.get(
`URL2/${id}`,
);
}
  • 暴露 api:
1
2
3
// path:src/services/api.ts

export * from './api/list';
  • 组件中使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// path:src/components/xxx.tsx

import React from 'react';
import * as api from '../../services/api';

class HomePage extends React.Component<any> {
/* 省略代码 */

async loadListData () {
try {
const res = await api.getListData();
this.setState({
listData: res.data.list,
});
} catch (error) {
// do something
}
}

/* 省略代码 */
}

export default HomePage;
  • 以上则成功完成 fetch 请求的封装。

Nextjs入门

发表于 2020-03-15 | 分类于 前端学习

Next.js

Next.js 是一个轻量级的 React 服务端渲染应用框架。有了它我们可以简单轻松的实现React的服务端渲染,从而加快首屏打开速度,也可以作SEO(收索引擎优化了)。在没有Next.js的时候,用React开发需要配置很多繁琐的参数,如Webpack配置,Router配置和服务器端配置等….。如果需要作SEO,要考虑的事情就更多了,怎么样服务端渲染和客户端渲染保持一致就是一件非常麻烦的事情,需要引入很多第三方库。但有了Next.js,这些问题都解决了,使开发人员可以将精力放在业务逻辑上,从繁琐的配置中解放出来。

简介

Next.js 是一个轻量级的 React 服务端渲染应用框架。

用一个框架,就要知道它的优点(或者是解决了我们什么问题):

  • 完善的React项目架构,搭建轻松。比如:Webpack配置,服务器启动,路由配置,缓存能力,这些在它内部已经完善的为我们搭建完成了。
  • 自带数据同步策略,解决服务端渲染最大难点。把服务端渲染好的数据,拿到客户端重用,这个在没有框架的时候,是非常复杂和困难的。有了Next.js,它为我们提供了非常好的解决方法,让我们轻松的就可以实现这些步骤。
  • 丰富的插件帮开发人员增加各种功能。每个项目的需求都是不一样的,包罗万象。无所不有,它为我们提供了插件机制,让我们可以在使用的时候按需使用。你也可以自己写一个插件,让别人来使用。
  • 灵活的配置,让开发变的更简单。它提供很多灵活的配置项,可以根据项目要求的不同快速灵活的进行配置。

目前Next.js是React服务端渲染的最佳解决方案,所以如果想使用React来开发需要SEO的应用,基本上就要使用Next.js。

create-next-app 快速创建Next.js项目

项目结构介绍:

  • components文件夹:这里是专门放置自己写的组件的,这里的组件不包括页面,指公用的或者有专门用途的组件。
  • node_modules文件夹:Next项目的所有依赖包都在这里,一般我们不会修改和编辑这里的内容。
  • pages文件夹:这里是放置页面的,这里边的内容会自动生成路由,并在服务器端渲染,渲染好后进行数据同步。
  • public文件夹: 这个是静态文件夹,比如项目需要的图片、图标和静态资源都可以放到这里。
  • .gitignore文件: 这个主要是控制git提交和上传文件的,简称就是忽略提交。
  • package.json文件:定义了项目所需要的文件和项目的配置信息(名称、版本和许可证),最主要的是使用npm install 就可以下载项目所需要的所有包。

Page和Component的使用

直接在pages文件夹下,新建一个xxx.js页面,写好相应的代码后,Next框架就自动做好了路由。如果要做更深的路由,在pages文件夹下再建相应的文件夹,然后在新的文件夹里面新建页面,以此类推即可。

pages里面的文件名和components文件夹里面的文件名可以相同,不会冲突。

在components文件夹目录新建组件,在pages里面引入即可。

路由-基础和基本跳转

路由跳转两种形式:

  • 标签式导航:利用标签<Link>

    引入:import Link from 'next/link'

    使用:<Link href="/"><a>返回首页</a></Link>

    注意:不写<a>标签时不支持兄弟标签并列,使用<a>便可使用

    1
    2
    3
    4
    5
    6
    <Link href="/jspangA">
    <a>
    <span>去JspangA页面</span>
    <span>前端博客</span>
    </a>
    </Link>
  • 编程式跳转:用js编程的方式进行跳转,也就是利用Router组件

    引入:import Router from 'next/router'

    使用: <button onClick={()=>{Router.push('/jspangA')}}>去JspangA页面</button>这种写法简单,但是耦合性太高,可以修改一下 ,把跳转放到一个方法里,然后调用方法。

    1
    2
    3
    4
    5
    function gotoA(){
    Router.push('/jspangA')
    }

    <button onClick={gotoA}>去JspangA页面</button>

路由-跳转时用query传递和接收参数

项目开发中一般需要动态跳转,动态跳转就是跳转时需要带一个参数或几个参数过去,然后在到达的页面接受这个传递的参数,并根据参数不同显示不同的内容。比如新闻列表,然后点击一个要看的新闻就会跳转到具体内容。这些类似这样的需求都都是通过传递参数实现的。

只能用query传递参数:在Next.js中只能通过通过query(?id=1)来传递参数,而不能通过(path:id)的形式传递参数。

标签式导航传递参数:

1
2
3
<Link href="/jpangA?name=技胖"><a>技胖</a></Link>
或者(优雅的写法)
<Link href={{pathname:'/jpangA',query:{name:'技胖'}}}><a>技胖</a></Link>

这种写法有两个参数,一个是pathname,一个是query,query里面包含传递的参数

编程式跳转传递参数:

1
2
3
4
5
6
7
function gotojpang(){
Router.push('/jpangA?name=技胖')
}

<div>
<button onClick={gotojpang}>技胖</button>
</div>

​ 或者:

1
2
3
4
5
6
7
8
function gotojpang(){
Router.push({
pathname:'/jpangA',
query:{
name:'技胖'
}
})
}

接受参数:withRouter是Next.js框架的高级组件,用来处理路由用的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//①引入withRouter
import {withRouter} from 'next/router'
import Link from 'next/link'

//②这里要传入参数router
const Jspang = ({router})=>{
return (
<>
//③通过这种形式获得参数
<div>{router.query.name},他来了</div>
<Link href="/"><a>返回首页</a></Link>
</>
)
}

//④导出要使用withRouter
export default withRouter(Jspang)

路由-六个钩子事件

路由的钩子事件,也就是当路由发生变化时,可以监听到这些变化事件,执行对应的函数。利用钩子事件是可以作很多事情的,比如转换时的加载动画,关掉页面的一些资源计数器…..

  • routerChangeStart路由发生变化时

    使用Router组件,然后用on方法来进行兼听

  • routerChangeComplete路由结束变化时

  • beforeHistoryChange浏览器history触发前

    history就是HTMP中的API,Next.js路由变化默认都是通过history进行的,所以每次都会调用。 不适用history的话,也可以通过hash。

    正确顺序为:①③②

  • routeChangeError路由跳转发生错误时

    注意:404找不到路由页面不算错误

转变成hash路由模式

以下两种事件都是针对hash的。

  • hashChangeStart:hash跳转开始时执行
  • hashChangeComplete:hash跳转完成时执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import React from 'react'
import Link from 'next/link'
import Router from 'next/router'

function gotojpang(){
Router.push('/jspang?name=技术胖')
}

//使用Router组件,on方法进行兼听
Router.events.on('routeChangeStart', (...args) => {
console.log('1.routeChangeStart->路由开始变化,参数为:', ...args)
})

Router.events.on('routeChangeComplete', (...args) => {
console.log('2.routeChangeComplete->路由结束变化,参数为:', ...args)
})

Router.events.on('beforeHistoryChange', (...args) => {
console.log('3,beforeHistoryChange->在改变浏览器 history之前触发,参数为:', ...args)
})

Router.events.on('routeChangeError', (...args) => {
console.log('4,routeChangeError->跳转发生错误,参数为:', ...args)
})

Router.events.on('hashChangeStart', (...args) => {
console.log('5,hashChangeStart->hash跳转开始时执行,参数为:', ...args)
})

Router.events.on('hashChangeComplete', (...args) => {
console.log('6,hashChangeComplete->hash跳转完成时,参数为:', ...args)
})
const Home = () => (

<>
<div>我是首页</div>
<div>
<Link href="/jspang?name=技胖"><a>技胖</a></Link>
<Link href="/jspang?name=术胖"><a>术胖</a></Link>
</div>
<div>
<button onClick={gotojpang}>技胖</button>
</div>

//hash模式
<div>
<Link href="#jspang"><a>技术胖</a></Link>
</div>
</>
)

export default Home

在getInitialProps中使用Axios获取远端数据

在Next.js框架中提供了getInitialProps静态方法用来获取远端数据,这个是框架的约定,所以你也只能在这个方法里获取远端数据。不要在生命周期里面获得,虽然可以,但是不符合约定。

安装axios: yarn add axios

引入: import axios from 'axios'

获取数据例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//使用getInitialProps远程获取数据
Jspang.getInitialProps = async ()=>{
const promise =new Promise((resolve)=>{
axios('https://www.easy-mock.com/xxx').then(
(res)=>{
console.log('远程数据结果:',res)
resolve(res.data.data)
}
)
})
return await promise
}

//获取数据之后,把得到的数据传递给页面组件,用{}显示出来就可以了。
//res.data.data里面有一个list数组
const Jspang = ({router,list})=>{
return (
<>
<div>{router.query.name},来了 .<br/>{list}</div>//直接就可以使用
<Link href="/"><a>返回首页</a></Link>
</>
)
}

使用Style JSX编写页面的CSS样式

在Next.js中引入一个CSS样式是不可以用的,如果想用,需要作额外的配置。因为框架为我们提供了一个style jsx特性,也就是把CSS用JSX的语法写出来。

一个特性:自动添加随机类名,不会污染全局css—加入了Style jsx代码后,Next.js会自动加入一个随机类名,这样就防止了CSS的全局污染。比如我们把代码写成下面这样,然后在浏览器的控制台中进行查看,你会发现自动给我们加入了类名,类似jsx-xxxxxxxx

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Jspang(){
return (
<>
<div>技术胖免费前端教程</div>
<div className="jspang">技术胖免费前端教程</div>
//使用这种形式些样式
<style jsx>
{`
div { color:blue;}
.jspang {color:red;}
`}
</style>
</>
)
}
export default Jspang

动态显示样式:

比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React, {useState} from 'react'
function Jspang(){
const [color,setColor] = useState('blue')
const changeColor=()=>{
setColor(color=='blue'?'red':'blue')
}
return (
<>
<div>技术胖免费前端教程</div>
<div><button onClick={changeColor}>改变颜色</button></div>
<style jsx>
{`
div { color:${color};}
`}
</style>
</>
)
}
export default Jspang

Lazy Loading实现模块懒加载

当项目越来越大的时候,模块的加载是需要管理的,如果不管理会出现首次打开过慢,页面长时间没有反应一系列问题。这时候可用Next.js提供的LazyLoading来解决这类问题。让模块和组件只有在用到的时候在进行加载,一般我把这种东西叫做“懒加载”.它一般分为两种情况,一种是懒加载(或者说是异步加载)模块,另一种是异步加载组件。

当我们作的应用存在首页打开过慢和某个页面加载过慢时,就可以采用Lazy Loading的形式,用懒加载解决这些问题。

懒加载模块:

比如我们引入开发中常用的模块Moment.js,它是一个JavaScript日期处理类库。安装:yarn add moment。

例如(未使用懒加载):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React, {useState} from 'react'
import moment from 'moment' //引入模块

function Time(){

const [nowTime,setTime] = useState(Date.now())

const changeTime=()=>{
//使用
setTime(moment(Date.now()).format())
}
return (
<>
<div>显示时间为:{nowTime}</div>
<div><button onClick={changeTime}>改变时间格式</button></div>
</>
)
}
export default Time

这个看起来很简单和清晰的案例,缺存在着一个潜在的风险,就是如何有半数以上页面使用了这个momnet的库,那它就会以公共库的形式进行打包发布,就算项目第一个页面不使用moment也会进行加载,这就是资源浪费,对于我这样有代码洁癖的良好程序员是绝对不允许的。下面我们就通过Lazy Loading来进行改造代码。

改良(使用懒加载):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import React, {useState} from 'react'
//删除import moment
function Time(){
const [nowTime,setTime] = useState(Date.now())

const changeTime= async ()=>{ //把方法变成异步模式
const moment = await import('moment') //等待moment加载完成
setTime(moment.default(Date.now()).format()) //注意使用defalut
}
return (
<>
<div>显示时间为:{nowTime}</div>
<div><button onClick={changeTime}>改变时间格式</button></div>
</>
)
}
export default Time

懒加载自定义组件

首先要在懒加载这个组件的文件汇总引入dynamic,import dynamic from 'next/dynamic'

使用:

1
2
3
4
5
6
7
8
9
10
11
import dynamic from 'next/dynamic' //引入dynamic
//使用如下方式引入组件
const One = dynamic(import('../components/one'))
function Time(){
return (
<>//使用
<One/>
</>
)
}
export default Time

写完代码后,可以看到自定义组件是懒加载的,只有在jsx里用到``时,才会被加载进来,如果不使用就不会被加载。

自定义Head更加友好的SEO操作

定制<Head>标签

  • 方法一:在各个页面加上<Head>标签(推荐)

    例如在pages中的某一个页面:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import Head from 'next/head' //引入Head
    function Header(){
    return (
    <>
    //使用Head
    <Head>
    <title>技术胖是最胖的!</title>
    <meta charSet='utf-8' />
    </Head>
    <div>JSPang.com</div>
    </>
    )
    }
    export default Header
  • 方法二:定义全局的<Head>

    这种方法相当于自定义了一个组件,然后把在组件里定义好,以后每个页面都使用这个组件,其实这种方法用处不大,也不灵活。因为Next.js已经把<Head>封装好了,本身就是一个组件,我们再次封装的意义不大。

Next.js框架下使用Ant Design UI

让Next.js支持CSS文件:

安装@zeit/next-css包,它的主要功能就是让Next.js可以加载CSS文件,有了这个包才可以进行配置:yarn add @zeit/next-css

配置:建立一个next.config.js(建在最外面的那个目录)这个就是Next.js的总配置文件。

1
2
3
4
5
6
7
const withCss = require('@zeit/next-css')

if(typeof require !== 'undefined'){
require.extensions['.css']=file=>{}
}

module.exports = withCss({})

按需加载Ant Design

加载Ant Design在我们打包的时候会把Ant Design的所有包都打包进来,这样就会产生性能问题,让项目加载变的非常慢。这肯定是不行的,现在的目的是只加载项目中用到的模块,这就需要我们用到一个babel-plugin-import文件。

先安装Ant Design库:yarn add antd

安装babel-plugin-import插件:yarn add babel-plugin-import

配置babel-plugin-import插件:在项目根目录建立.babelrc文件,然后写入如下配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
{	//Next.js的总配置文件,相当于继承了它本身的所有配置
"presets":["next/babel"],
"plugins":[
//增加新的插件,这个插件就是让antd可以按需引入,包括CSS
[
"import",
{
"libraryName":"antd",
"style":"css"
}
]
]
}

配置好了以后,webpack就不会默认把整个Ant Design的包都进行打包到生产环境了,而是我们使用那个组件就打包那个组件,同样CSS也是按需打包的。

使用:

1
2
3
4
5
6
7
8
import {Button} from 'antc'
function Page(){
return(
<>
<Button>我是按需引入的按钮</Button>
</>
)
}

Next.js生产环境打包

其实Next.js大打包时非常简单的,只要一个命令就可以打包成功。但是当你使用了Ant Desgin后,在打包的时候会遇到一些坑。

打包 :next build

运行:next start -p 80

先把这两个命令配置到package.json文件里,比如配置成下面的样子。

1
2
3
4
5
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start -p 80"
},

然后在终端里运行一下yarn build,如果这时候报错,其实是我们在加入Ant Design的样式时产生的,你可以改用全局引入CSS解决问题。

在page目录下,新建一个_app.js文件,然后写入下面的代码。

1
2
3
4
5
import App from 'next/app'

import 'antd/dist/antd.css'

export default App

这样配置一下,就可以打包成功了,然后再运行yarn start来运行服务器,看一下我们的header页面,也是有样式的。说明打包已经成功了。

Nginx基础

发表于 2020-03-15 | 分类于 Linux

Nginx

Nginx是一款轻量级的HTTP服务器,采用事件驱动的异步非阻塞处理方式框架,这让其具有极好的IO性能,时常用于服务端的反向代理和负载均衡。

初识Nginx和环境准备

Nginx的优点

  • 支持海量高并发:采用IO多路复用epoll。官方测试Nginx能够支持5万并发链接,实际生产环境中可以支撑2-4万并发连接数。
  • 内存消耗少:在主流的服务器中Nginx目前是内存消耗最小的了,比如我们用Nginx+PHP,在3万并发链接下,开启10个Nginx进程消耗150M内存。
  • 免费使用可以商业化:Nginx为开源软件,采用的是2-clause BSD-like协议,可以免费使用,并且可以用于商业。
  • 配置文件简单:网络和程序配置通俗易懂,即使非专业运维也能看懂。
  • 反向代理功能,负载均衡功能等

可以通过https://w3techs.com/这个网站看到nginx的热度。

阿里云校园生态:https://promotion.aliyun.com/ntms/act/campus2018.html

用yum进行安装必要程序

1
2
yum -y install gcc gcc-c++ autoconf pcre-devel make automake
yum -y install wget httpd-tools vim

Nginx的快速搭建

Nginx版本说明

  • Mainline version :开发版,主要是给广大Nginx爱好者,测试、研究和学习的,但是不建议使用于生产环境。
  • Stable version : 稳定版,也就是我们说的长期更新版本。这种版本一般比较成熟,经过长时间的更新测试,所以这种版本也是主流版本。
  • legacy version : 历史版本,如果你需要以前的版本,Nginx也是有提供的。

基于Yum的方式安装Nginx

  • 检查yum是否存在:yum list | grep nginx

  • 若原来源版本过低,可以自行配置yum源:

    1
    2
    3
    4
    5
    6
    7
    vim /etc/yum.repos.d/nginx.repo  #先进入到指定文件
    #再添加如下代码
    [nginx]
    name=nginx repo
    baseurl=http://nginx.org/packages/OS/OSRELEASE/$basearch/ #这里OS换成centos,OSRELEASE换成7;视情况而定
    gpgcheck=0
    enabled=1
  • 配置好yum源后,安装nginx:yum install nginx

  • 安装好后,检测Nginx版本:nginx -v

Nginx基本配置文件详解

查看Nginx的安装目录

rpm -ql nginx这条命令可以找到nginx的所有安装位置。

nginx.conf 文件解读

nginx.conf 文件是Nginx总配置文件,在我们搭建服务器时经常调整的文件。

进入etc/nginx目录,用vim打开nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#运行用户,默认即是nginx,可以不进行设置
user nginx;
#Nginx进程,一般设置为和CPU核数一样
worker_processes 1;
#错误日志存放目录
error_log /var/log/nginx/error.log warn;
#进程pid存放位置
pid /var/run/nginx.pid;


events {
worker_connections 1024; # 单个后台进程的最大并发数
}


http {
include /etc/nginx/mime.types; #文件扩展名与类型映射表
default_type application/octet-stream; #默认文件类型
#设置日志模式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main; #nginx访问日志存放位置

sendfile on; #开启高效传输模式
#tcp_nopush on; #减少网络报文段的数量

keepalive_timeout 65; #保持连接的时间,也叫超时时间

#gzip on; #开启gzip压缩

include /etc/nginx/conf.d/*.conf; #包含的子配置项位置和文件

default.conf 配置项讲解

我们看到最后有一个子文件的配置项,那我们打开这个include子文件配置项看一下里边都有些什么内容。

进入conf.d目录,然后使用vim default.conf进行查看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
server {
listen 80; #配置监听端口
server_name localhost; //配置域名

#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;

location / {
root /usr/share/nginx/html; #服务默认启动目录
index index.html index.htm; #默认访问文件
}

#error_page 404 /404.html; # 配置404页面

# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html; #错误状态码的显示页面,配置后需要重启
location = /50x.html {
root /usr/share/nginx/html;
}

# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}

# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}

明白了这些配置项,我们知道我们的服务目录放在了/usr/share/nginx/html下,可以使用命令进入看一下目录下的文件。

1
2
cd /usr/share/nginx/html
ls

可以看到目录下面有两个文件,50x.html 和 index.html。我们可以使用vim进行编辑。

阿里云的安全组配置

如果你使用的是阿里云,记得到ECS实例一下打开端口。

步骤如下:

  1. 进入阿里云控制台,并找到ECS实例。
  2. 点击实例后边的“更多”
  3. 点击“网络和安全组” ,再点击“安全组配置”
  4. 右上角添加“安全组配置”
  5. 进行80端口的设置。

Nginx服务启动、停止、重启

启动Nginx服务

  • 直接启动:nginx
  • 使用systemctl命令启动:systemctl start nginx.service
  • 检查是否启动:ps aux | grep nginx

停止Nginx服务

  • 立即停止:nginx -s stop,这种方法比较强硬,无论进程是否在工作,都直接停止进程。
  • 从容停止服务:nginx -s quit,这种方法较stop相比就比较温和一些了,需要进程完成当前工作后再停止。
  • killall 方法杀死进程:killall nginx,也是比较野蛮的方法,当上面方法没起作用的时候,可以用这种。
  • systemctl停止:systemctl stop nginx.service

重启Nginx服务

  • 重启服务:systemctl restart nginx.service
  • 重新载入配置文件:nginx -s reload,在重新编写或者修改Nginx的配置文件后,都需要作一下重新载入。

查看端口号

在默认情况下,Nginx启动后会监听80端口,从而提供HTTP访问,如果80端口已经被占用则会启动失败。我么可以使用netstat -tlnp命令查看端口号的占用情况。

自定义错误页

真正好的网站会武装到牙齿,即便是不同种类的错误页面的显示

多错误指向一个页面

在/etc/nginx/conf.d/default.conf 是可以看到下面这句话的。

1
error_page   500 502 503 504  /50x.html;

error_page指令用于自定义错误页面,500,502,503,504 这些就是HTTP中最常见的错误代码,/50.html 用于表示当发生上述指定的任意一个错误的时候,都是用网站根目录下的/50.html文件进行处理。

单独为错误指定处理方式

有些时候是要把这些错误页面单独的表现出来,给用户更好的体验。所以就要为每个错误码设置不同的页面。设置方法如下:

1
error_page 404  /404.html;

然后到网站目录下新建一个404.html 文件,并写入一些信息。

1
2
3
4
5
6
<html>
<meta charset="UTF-8">
<body>
<h1>404页面没有找到!</h1>
</body>
</html>

然后重启我们的服务,再进行访问,你会发现404页面发生了变化。

把错误码换成一个地址

处理错误的时候,不仅可以只使用本服务器的资源,还可以使用外部的资源。比如我们将配置文件设置成这样。

1
error_page  404 http://jspang.com;

我们使用了技术胖的博客地址作为404页面没有找到的提示,就形成了,没有找到文件,就直接跳到了技术胖的博客上了。

Nginx访问权限

简单实现访问控制

有时候我们的服务器只允许特定主机访问,比如内部OA系统,或者应用的管理后台系统,更或者是某些应用接口,这时候我们就需要控制一些IP访问,我们可以直接在location里进行配置。

可以直接在default.conf里进行配置。

1
2
3
4
location / {
deny 123.9.51.42; #禁止这个ip地址访问
allow 45.76.202.231; #允许这个ip地址访问
}

配置完成后,重启一下服务器就可以实现限制和允许访问了。

指定优先级

我们先来看一下代码:

1
2
3
4
location / {
allow 45.76.202.231;
deny all;
}

上面的配置表示只允许45.76.202.231进行访问,其他的IP是禁止访问的。但是如果我们把deny all指令,移动到 allow 45.76.202.231之前,会发生什么那?会发现所有的IP都不允许访问了。这说明了一个问题:就是在同一个块下的两个权限指令,先出现的设置会覆盖后出现的设置(也就是谁先触发,谁起作用)。

复杂访问控制权限匹配

在工作中,访问权限的控制需求更加复杂,例如,对于网站下的img(图片目录)是运行所有用户访问,但对于网站下的admin目录则只允许公司内部固定IP访问。这时候仅靠deny和allow这两个指令,是无法实现的。我们需要location块来完成相关的需求匹配。

上面的需求,配置代码如下:

1
2
3
4
5
6
location =/img{
allow all;
}
location =/admin{
deny all;
}

=号代表精确匹配,使用了=后是根据其后的模式进行精确匹配。这个直接关系到我们网站的安全,一定要学会。

使用正则表达式设置访问权限

只有精确匹配有时是完不成我们的工作任务的,比如现在我们要禁止访问所有php的页面,php的页面大多是后台的管理或者接口代码,所以为了安全我们经常要禁止所有用户访问,而只开放公司内部访问的。

代码如下:

1
2
3
location ~\.php$ {
deny all;
}

这样我们再访问的时候就不能访问以php结尾的文件了。这样让网站变的安全很多了。

Nginx设置虚拟主机

虚拟主机是指在一台物理主机服务器上划分出多个磁盘空间,每个磁盘空间都是一个虚拟主机,每台虚拟主机都可以对外提供Web服务,并且互不干扰。在外界看来,虚拟主机就是一台独立的服务器主机,这意味着用户能够利用虚拟主机把多个不同域名的网站部署在同一台服务器上,而不必再为建立一个网站单独购买一台服务器,既解决了维护服务器技术的难题,同时又极大地节省了服务器硬件成本和相关的维护费用。

我们可以用一台服务器,建立多个网站,为其划分不同端口即可。

配置虚拟主机可以基于端口号、基于IP和基于域名。

基于端口号配置虚拟主机

原理就是Nginx监听多个端口,根据不同的端口号,来区分不同的网站。

我们可以直接配置在主文件里etc/nginx/nginx.conf文件里, 也可以配置在子配置文件里etc/nginx/conf.d/default.conf。我这里为了配置方便,就配置在子文件里了。当然你也可以再新建一个文件,只要在conf.d文件夹下就可以了。

修改配置文件中的server选项,这时候就会有两个server。

1
2
3
4
5
6
server{
listen 8001;
server_name localhost;
root /usr/share/nginx/html/html8001;
index index.html;
}

编在usr/share/nginx/html/html8001/目录下的index.html文件并查看结果。

1
<h1>welcome port 8001</h1>

最后在浏览器中分别访问地址和带端口的地址。看到的结果是不同的。

然后我们就可以在浏览器中访问http://112.74.164.244:8001了。

基于IP的虚拟主机

基于IP和基于端口的配置几乎一样,只是把server_name选项,配置成IP就可以了。

比如上面的配置,我们可以修改为:

1
2
3
4
5
6
server{
listen 80;
server_name 112.74.164.244;
root /usr/share/nginx/html/html8001;
index index.html;
}

基于域名配置虚拟主机

在真实的上线环境中,一个网站是需要域名和公网IP才可以访问的。

先要对域名进行解析,这样域名才能正确定位到你需要的IP上。 我这里新建了两个解析,分别是:

  • nginx.jspang.com :这个域名映射到默认的Nginx首页位置。
  • nginx2.jspang.com : 这个域名映射到原来的8001端口的位置。

我们修改etc/nginx/conf.d目录下的default.conf 文件,把原来的80端口虚拟主机改为以域名划分的虚拟主机。代码如下:

1
2
3
server {
listen 80;
server_name nginx.jspang.com;

我们再把同目录下的8001.conf文件进行修改,改成如下:

1
2
3
4
5
6
7
8
server{
listen 80;
server_name nginx2.jspang.com;
location / {
root /usr/share/nginx/html/html8001;
index index.html index.htm;
}
}

然后我们用平滑重启的方式,进行重启,这时候我们在浏览器中访问这两个网页。

其实域名设置虚拟主机也非常简单,主要操作的是配置文件的server_name项,还需要域名解析的配合。

Nginx反向代理设置

现在的web模式基本的都是标准的CS结构,即Client端到Server端。那代理就是在Client端和Server端之间增加一个提供特定功能的服务器,这个服务器就是我们说的代理服务器。

正向代理:如果你觉的反向代理不好理解,那先来了解一下正向代理。比如翻墙工具(我这里说的不是物理梯子),它就是一个典型的正向代理工具。它会把我们不让访问的服务器的网页请求,代理到一个可以访问该网站的代理服务器上来,一般叫做proxy服务器,再转发给客户。

img简单来说就是你想访问目标服务器的权限,但是没有权限。这时候代理服务器有权限访问服务器,并且你有访问代理服务器的权限,这时候你就可以通过访问代理服务器,代理服务器访问真实服务器,把内容给你呈现出来。

反向代理:反向代理跟代理正好相反(需要说明的是,现在基本所有的大型网站的页面都是用了反向代理),客户端发送的请求,想要访问server服务器上的内容。发送的内容被发送到代理服务器上,这个代理服务器再把请求发送到自己设置好的内部服务器上,而用户真实想获得的内容就在这些设置好的服务器上。img

通过图片的对比,应该看出一些区别,这里proxy服务器代理的并不是客户端,而是服务器,即向外部客户端提供了一个统一的代理入口,客户端的请求都要先经过这个proxy服务器。具体访问那个服务器server是由Nginx来控制的。再简单点来讲,一般代理指代理的客户端,反向代理是代理的服务器。

反向代理的好处和用途

  • 安全性:正向代理的客户端能够在隐藏自身信息的同时访问任意网站,这个给网络安全代理了极大的威胁。因此,我们必须把服务器保护起来,使用反向代理客户端用户只能通过外来网来访问代理服务器,并且用户并不知道自己访问的真实服务器是那一台,可以很好的提供安全保护。
  • 功能性:反向代理的主要用途是为多个服务器提供负债均衡、缓存等功能。负载均衡就是一个网站的内容被部署在若干服务器上,可以把这些机子看成一个集群,那Nginx可以将接收到的客户端请求“均匀地”分配到这个集群中所有的服务器上,从而实现服务器压力的平均分配,也叫负载均衡。

最简单的反向代理

现在我们要访问http://nginx2.jspang.com然后反向代理到jspang.com这个网站。我们直接到etc/nginx/con.d/8001.conf进行修改。

修改后的配置文件如下:

1
2
3
4
5
6
7
8
server{
listen 80;
server_name nginx2.jspang.com;
location / {
#使用proxy_pass指令
proxy_pass http://jspang.com;
}
}

一般我们反向代理的都是一个IP,但是我这里代理了一个域名也是可以的。其实这时候我们反向代理就算成功了,我们可以在浏览器中打开http://nginx2.jspang.com来测试一下。

其它反向代理指令

  • proxy_set_header :在将客户端请求发送给后端服务器之前,更改来自客户端的请求头信息。
  • proxy_connect_timeout:配置Nginx与后端代理服务器尝试建立连接的超时时间。
  • proxy_read_timeout : 配置Nginx向后端服务器组发出read请求后,等待相应的超时时间。
  • proxy_send_timeout:配置Nginx向后端服务器组发出write请求后,等待相应的超时时间。
  • proxy_redirect :用于修改后端服务器返回的响应头中的Location和Refresh。

Nginx适配PC或移动端

现在很多网站都是有了PC端和H5站点的,因为这样就可以根据客户设备的不同,显示出体验更好的,不同的页面了。

这样的需求有人说拿自适应就可以搞定,比如我们常说的bootstrap和24格布局法,这些确实是非常好的方案,但是无论是复杂性和易用性上面还是不如分开编写的好,比如我们常见的淘宝、京东……这些大型网站就都没有采用自适应,而是用分开制作的方式。

那分开制作如何通过配置Nginx来识别出应该展示哪个页面呢?

$http_user_agent的使用:

Nginx通过内置变量$http_user_agent,可以获取到请求客户端的userAgent,就可以用户目前处于移动端还是PC端,进而展示不同的页面给用户。

操作步骤如下:

  1. 在/usr/share/nginx/目录下新建两个文件夹,分别为:pc和mobile目录

    1
    2
    3
    cd /usr/share/nginx
    mkdir pc
    mkdir mobile
  2. 在pc和moblic目录下,新建两个index.html文件,文件里下面内容

    1
    <h1>I am pc!</h1>
    1
    <h1>I am mobile!</h1>
  3. 进入etc/nginx/conf.d目录下,修改8001.conf文件,改为下面的形式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    server{
    listen 80;
    server_name nginx2.jspang.com;
    location / {
    root /usr/share/nginx/pc;
    if ($http_user_agent ~* '(Android|webOS|iPhone|iPod|BlackBerry)') {
    root /usr/share/nginx/mobile;
    }
    index index.html;
    }
    }

Nginx的Gzip压缩配置

Gzip是网页的一种网页压缩技术,经过gzip压缩后,页面大小可以变为原来的30%甚至更小。更小的网页会让用户浏览的体验更好,速度更快。gzip网页压缩的实现需要浏览器和服务器的支持。

gzip是需要服务器和浏览器同事支持的。当浏览器支持gzip压缩时,会在请求消息中包含Accept-Encoding:gzip,这样Nginx就会向浏览器发送听过gzip后的内容,同时在相应信息头中加入Content-Encoding:gzip,声明这是gzip后的内容,告知浏览器要先解压后才能解析输出。

gzip的配置项

Nginx提供了专门的gzip模块,并且模块中的指令非常丰富。

  • gzip : 该指令用于开启或 关闭gzip模块。
  • gzip_buffers : 设置系统获取几个单位的缓存用于存储gzip的压缩结果数据流。
  • gzip_comp_level : gzip压缩比,压缩级别是1-9,1的压缩级别最低,9的压缩级别最高。压缩级别越高压缩率越大,压缩时间越长。
  • gzip_disable : 可以通过该指令对一些特定的User-Agent不使用压缩功能。
  • gzip_min_length:设置允许压缩的页面最小字节数,页面字节数从相应消息头的Content-length中进行获取。
  • gzip_http_version:识别HTTP协议版本,其值可以是1.1.或1.0.
  • gzip_proxied : 用于设置启用或禁用从代理服务器上收到相应内容gzip压缩。
  • gzip_vary : 用于在响应消息头中添加Vary:Accept-Encoding,使代理服务器根据请求头中的Accept-Encoding识别是否启用gzip压缩。

gzip最简单的配置

1
2
3
4
5
6
http {
.....
gzip on;
gzip_types text/plain application/javascript text/css;
.....
}

gzip on是启用gizp模块,下面的一行是用于在客户端访问网页时,对文本、JavaScript 和CSS文件进行压缩输出。

配置好后,我们就可以重启Nginx服务,让我们的gizp生效了。

如果你是windows操作系统,你可以按F12键打开开发者工具,单机当前的请求,在标签中选择Headers,查看HTTP响应头信息。你可以清楚的看见Content-Encoding为gzip类型。

网页GZIP压缩检测

React Hooks

发表于 2020-03-15 | 分类于 前端学习

React Hooks

React Hooks 简介

React Hooks就是用函数形式代替原来的继承类的形式,并且使用预函数的形式管理state,有Hooks可以不再使用类的形式定义组件了。原来把组件分为有状态组件和无状态组件,有状态组件用类的形式声明,无状态组件用函数的形式声明。现在所有的组件都可以用函数来声明了。

Hooks本质上就是一类特殊的函数,他们可以为你的函数型组件(function component)注入一些特殊的功能。

原始写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React, { Component } from 'react';

class Example extends Component {
constructor(props) {
super(props);
this.state = { count:0 }
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={this.addCount.bind(this)}>Chlick me</button>
</div>
);
}
addCount(){
this.setState({count:this.state.count+1})
}
}

export default Example;

React Hooks 写法:

1
2
3
4
5
6
7
8
9
10
11
import React, { useState } from 'react';
function Example(){
const [ count , setCount ] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={()=>{setCount(count+1)}}>click me</button>
</div>
)
}
export default Example;

useState

1
const [ count , setCount ] = useState(0);

count为定义的变量,为它赋予初始值0,setCount为其对应的方法;

1
<p>You clicked {count} times</p>

读取它的值,只要使用{count}就可以了

1
<button onClick={()=>{setCount(count+1)}}>click me</button>

直接调用setCount函数,这个函数接收的参数是修改过的新状态值 。

接下来的事情就交给React,他会重新渲染组件。React自动帮助我们记忆了组件的上一次状态值 。

React Hooks不能出现在条件判断语句中,因为它必须有完全一样的渲染顺序。

useEffect

代替componentDidMount和componentDidUpdate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React, { useState , useEffect } from 'react';
function Example(){
const [ count , setCount ] = useState(0);

useEffect(()=>{
console.log(`useEffect=>You clicked ${count} times`)
})

return (
<div>
<p>You clicked {count} times</p>
<button onClick={()=>{setCount(count+1)}}>click me</button>
</div>
)
}
export default Example;

注意:

  1. React首次渲染和之后的 每次渲染都会调用一遍useEffect函数,而之前我们要用两个生命周期函数分别表示首次渲染(componentDidMonut)和更新导致的重新渲染(componentDidUpdate)。
  2. useEffect中定义的函数的执行不会阻碍浏览器更新视图,也就是说这些函数时异步执行的,而componentDidMonut和componentDidUpdate中的代码都是同步执行的。个人认为这个有好处也有坏处吧,比如我们要根据页面的大小,然后绘制当前弹出窗口的大小,如果时异步的就不好操作了。

实现componentWillUnmount生命周期函数

在写React应用的时候,在组件中经常用到componentWillUnmount生命周期函数(组件将要被卸载时执行)。比如我们的定时器要清空,避免发生内存泄漏;比如登录状态要取消掉,避免下次进入信息出错。

1
2
3
4
5
6
7
8
9
function Index() {
useEffect(()=>{
console.log('useEffect=>老弟你来了!Index页面')
return ()=>{
console.log('老弟,你走了!Index页面')
}
},[])
return <h2>JSPang.com</h2>;
}

return用与解绑组件。

useEffect的第二个参数,它是一个数组,数组中可以写入很多状态对应的变量,意思是当状态值发生变化时,我们才进行解绑。但是当传空数组[]时,就是当组件将被销毁时才进行解绑,这也就实现了componentWillUnmount的生命周期函数。

useContext

useContext,它可以帮助我们跨越组件层级直接传递变量,实现共享。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import React, { useState , createContext } from 'react';
//===关键代码
const CountContext = createContext()

function Example4(){
const [ count , setCount ] = useState(0);

return (
<div>
<p>You clicked {count} times</p>
<button onClick={()=>{setCount(count+1)}}>click me</button>

<CountContext.Provider value={count}>
<Counter />
</CountContext.Provider>

</div>
)
}

//子组件
function Counter(){
const count = useContext(CountContext) //一句话就可以得到count
return (<h2>{count}</h2>)
}

export default Example4;

使用const CountContext = createContext()创建全局上下文;再使用CountContext.Provider实现共享,在子组件中使用useContext()接收值。

useReducer

reducer其实就是一个函数,这个函数接收两个参数,一个是状态,一个用来控制业务逻辑的判断参数 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React, { useReducer } from 'react';

function ReducerDemo(){
const [ count , dispatch ] =useReducer((state,action)=>{
switch(action){
case 'add':
return state+1
case 'sub':
return state-1
default:
return state
}
},0)
return (
<div>
<h2>现在的分数是{count}</h2>
<button onClick={()=>dispatch('add')}>Increment</button>
<button onClick={()=>dispatch('sub')}>Decrement</button>
</div>
)
}
export default ReducerDemo

useMemo

useMemo主要用来解决使用React hooks产生的无用渲染的性能问题。使用function的形式来声明组件,失去了shouldCompnentUpdate(在组件更新之前)这个生命周期,也就是说我们没有办法通过组件更新前条件来决定组件是否更新。而且在函数组件中,也不再区分mount和update两个状态,这意味着函数组件的每一次调用都会执行内部的所有逻辑,就带来了非常大的性能损耗。useMemo和useCallback都是解决上述性能问题的 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import React , {useState,useMemo} from 'react';

//父组件
function Example3(){
const [count1 , setCount1] = useState(0)
const [count2 , setCount2] = useState(100)
return (
<>
<button onClick={()=>{setCount1(count1+1)}}>count1加1</button>
<button onClick={()=>{setCount2(count2-1)}}>count2减1</button>
<ChildComponent name={count2}>{count1}</ChildComponent>
</>
)
}

//子组件
function ChildComponent({name,children}){
function changeCount2(name){
console.log('count2减1了!!')
return name
}

const actionCount2 = useMemo(() => changeCount2(name), [name])
// const actionCount2 = changeCount2(name)
return (
<>
<div>count1:{children}</div>
<div>count2:{actionCount2}</div>
</>
)
}

自定义Hooks函数

其实自定义Hooks函数和用Hooks创建组件很相似,跟我们平时用JavaScript写函数几乎一模一样,可能就是多了些React Hooks的特性,自定义Hooks函数偏向于功能,而组件偏向于界面和业务逻辑。由于差别不大,所以使用起来也是很随意的。如果是小型项目是可以的,但是如果项目足够复杂,这会让项目结构不够清晰。所以学习自定义Hooks函数还是很有必要的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function useWinSize(){
const [ size , setSize] = useState({
width:document.documentElement.clientWidth,
height:document.documentElement.clientHeight
})

const onResize = useCallback(()=>{
setSize({
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
})
},[])
useEffect(()=>{
window.addEventListener('resize',onResize)
return ()=>{
window.removeEventListener('resize',onResize)
}
},[])

return size;
}

function Example9(){

const size = useWinSize()
return (
<div>页面Size:{size.width}x{size.height}</div>
)
}

export default Example9

react生命周期

发表于 2020-03-15 | 分类于 前端学习

react生命周期

React 生命周期图

React声明周期图

React生命周期四大阶段:

  1. Initialization:初始化阶段。
  2. Mounting: 挂载阶段。
  3. Updation: 更新阶段。
  4. Unmounting: 销毁阶段

什么是生命周期函数?

一句话:

生命周期函数指在某一个时刻组件会自动调用执行的函数。

比如:todo里的reder()函数就是一个生命周期函数,它在 state发生改变时自动执行。这就是一个标准的自动执行函数。

  • constructor不算生命周期函数。

constructor我们叫构造函数,它是ES6的基本语法。虽然它和生命周期函数的性质一样,但不能认为是生命周期函数。

但是你要心里把它当成一个生命周期函数,可以看成React的Initialization阶段,定义属性(props)和状态(state)。

Mounting阶段(挂载阶段)

Mounting阶段伴随着整个虚拟DOM的生成,它里面包括三个小的生命周期函数,分别是:

  1. componentWillMount : 在组件即将被挂载到页面的时刻执行。

  2. render : 页面state或props发生变化时执行。

    render函数会插入jsx生成的dom结构,react会生成一份虚拟dom树,在每一次组件更新时,在此react会通过其diff算法比较更新前后的新旧DOM树,比较以后,找到最小的有差异的DOM节点,并重新渲染

  3. componentDidMount : 组件挂载完成时被执行。

    组件第一次渲染完成,此时的dom节点已经生成,可以在这里调用ajax请求,返回数据setState后组件会重新渲染

  • componentWillMount和componentDidMount这两个生命周期函数,只在页面刷新时执行一次,而render函数是只要有state和props变化就会执行

Updation阶段(更新阶段)

Updation阶段是组件发生改变的更新阶段,这是React生命周期中比较复杂的一部分,它有两个基本部分组成,一个是props属性改变,一个是state状态改变

  • shouldComponentUpdate函数

    shouldComponentUpdate函数会在组件更新之前,自动被执行。 它要求返回一个布尔类型的结果,必须有返回值 , 返回true,就同意组件更新;返回false,就反对组件更新。

    shouldComponentUpdate有两个参数:

    • nextProps:变化后的属性;

    • nextState:变化后的状态;

    • 1
      2
      3
      4
      5
      6
      7
      8
      //避免子组件频繁无用渲染render
      shouldComponentUpdate(nextProps,nextState){
      if(nextProps.content !== this.props.content){
      return true
      }else{
      return false
      }
      }
  • componentWillUpadate函数

    componentWillUpdate在组件更新之前,但shouldComponenUpdate之后被执行。但是如果shouldComponentUpdate返回false,这个函数就不会被执行了。

  • componentDidUpdate函数

    componentDidUpdate在组件更新之后执行,它是组件更新的最后一个环节。

  • componentWillReceiveProps函数

    子组件接收到父组件传递过来的参数,父组件render函数重新被执行,这个生命周期就会被执行。

    • 也就是说这个组件第一次存在于Dom中,函数是不会被执行的;
    • 如果已经存在于Dom中,函数才会被执行。

Unmounting阶段(卸载阶段)

  • componentWillUnmount函数

    这个函数是组件从页面中删除的时候执行 。

    1. clear你在组件中所有的setTimeout、setInterval
    2. 移除所有组件中的兼听 removeEventListener

参考:

技术胖

react生命周期基本用法

利用react-router4的react-router-config做路由鉴权

发表于 2020-03-15 | 分类于 前端学习

利用react-router4的react-router-config做路由鉴权

文章来源:https://segmentfault.com/a/1190000015282620

一、react-router-config 是一个帮助我们配置静态路由的小助手。
其源码就是一个高阶函数 利用一个map函数生成静态路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React from "react";
import Switch from "react-router/Switch";
import Route from "react-router/Route";
const renderRoutes = (routes, extraProps = {}, switchProps = {}) =>
routes ? (
<Switch {...switchProps}>
{routes.map((route, i) => (
<Route
key={route.key || i}
path={route.path}
exact={route.exact}
strict={route.strict}
render={props => (
<route.component {...props} {...extraProps} route={route} />
)}
/>
))}
</Switch>
) : null;
export default renderRoutes;

//router.js 假设这是我们设置的路由数组(这种写法和vue很相似是不是?)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const routes = [
{ path: '/',
exact: true,
component: Home,
},
{
path: '/login',
component: Login,
},
{
path: '/user',
component: User,
},
{
path: '*',
component: NotFound
}
]

//app.js 那么我们在app.js里这么使用就能帮我生成静态的路由了

1
2
3
4
5
6
7
8
9
10
11
import { renderRoutes } from 'react-router-config'
import routes from './router.js'
const App = () => (
<main>
<Switch>
{renderRoutes(routes)}
</Switch>
</main>
)

export default App

扯了半天,要如何利用这个插件帮我们路由鉴权呢?
用过vue的小朋友都知道,vue的router.js 里面添加 meta: { requiresAuth: true }
然后利用导航守卫

1
2
3
router.beforeEach((to, from, next) => {
// 在每次路由进入之前判断requiresAuth的值,如果是true的话呢就先判断是否已登陆
})

二、基于类似vue的路由鉴权想法,我们稍稍改造一下react-router-config
// utils/renderRoutes.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React from 'react'
import { Route, Redirect, Switch } from 'react-router-dom'
const renderRoutes = (routes, authed, authPath = '/login', extraProps = {}, switchProps = {}) => routes ? (
<Switch {...switchProps}>
{routes.map((route, i) => (
<Route
key={route.key || i}
path={route.path}
exact={route.exact}
strict={route.strict}
render={(props) => {
if (!route.requiresAuth || authed || route.path === authPath) {
return <route.component {...props} {...extraProps} route={route} />
}
return <Redirect to={{ pathname: authPath, state: { from: props.location } }} />
}}
/>
))}
</Switch>
) : null

export default renderRoutes

修改后的源码增加了两个参数 authed 、 authPath 和一个属性 route.requiresAuth
然后再来看一下最关键的一段代码

1
2
3
4
if (!route.requiresAuth || authed || route.path === authPath) {
return <route.component {...props} {...extraProps} route={route} />
}
return <Redirect to={{ pathname: authPath, state: { from: props.location } }} />

很简单 如果 route.requiresAuth = false 或者 authed = true 或者 route.path === authPath(参数默认值’/login’)则渲染我们页面,否则就渲染我们设置的authPath页面,并记录从哪个页面跳转。

相应的router.js也要稍微修改一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const routes = [
{ path: '/',
exact: true,
component: Home,
requiresAuth: false,
},
{
path: '/login',
component: Login,
requiresAuth: false,

},
{
path: '/user',
component: User,
requiresAuth: true, //需要登陆后才能跳转的页面

},
{
path: '*',
component: NotFound,
requiresAuth: false,
}
]

//app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import React from 'react'
import { Switch } from 'react-router-dom'
//import { renderRoutes } from 'react-router-config'
import renderRoutes from './utils/renderRoutes'
import routes from './router.js'

const authed = false // 如果登陆之后可以利用redux修改该值(关于redux不在我们这篇文章的讨论范围之内)
const authPath = '/login' // 默认未登录的时候返回的页面,可以自行设置

const App = () => (
<main>
<Switch>
{renderRoutes(routes, authed, authPath)}
</Switch>
</main>
)
export default App
//登陆之后返回原先要去的页面login函数
login(){
const { from } = this.props.location.state || { from: { pathname: '/' } }
// authed = true // 这部分逻辑自己写吧。。。
this.props.history.push(from.pathname)
}

以上~修改了部分源码并完成了我们想要的效果。

作用域

发表于 2020-03-15 | 分类于 前端学习

作用域

什么是作用域?

作用域是代码在运行时,某些特定部分中的变量,函数,和对象的可访问性。作用域负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。换句话说,作用域决定了变量和函数的可访问范围,即作用域控制着变量和函数的可见性和生命周期。

JavaScript中的作用域

  • 全局作用域
  • 局部作用域

如果一个变量在函数外或者大括号{}外声明的,那么就定义了一个全局作用域;在ES6之前局部作用域只包含了函数作用域,ES6为我们提供了块级作用域,也属于局部作用域。

全局作用域

拥有全局作用域的对象可以在代码的任何地方访问到。

以下情形拥有全局作用域:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var a = 5;           //①最外层变量

function func(){ //②最外层函数
//...
}

function func1(){
a = 3; //③未经定义直接赋值的变量(由于变量提升使之成为全局变量)
var b = 4;
}

function func2(){
window.a = 5; //④通过window来添加一个全局变量
}

局部作用域

局部作用域一般只能在固定代码片段中可以访问到。最常见的为函数作用域

函数作用域

定义在函数中的变量就在函数作用域中。并且函数在每次调用时都有一个不同的作用域。这意味着同名变量可以用在不同的函数中。因为这些变量绑定在不同的函数中,拥有不同作用域,彼此之间不能访问。

函数作用域:

1
2
3
4
5
function func(){
var a = 5; //局部变量,【注意】:不能省略var,否则会因为变量提升成为全局变量
console.log(a);//函数内可以访问
}
console.log(a);//函数外不可访问

块级作用域测试:

1
2
3
4
for(var i = 0; i < 3; i++){
var num+=i;
}
console.log(i);//3 ---此处for语句块内部与外面是同一个作用域

关于变量提升

在Javascript中,函数及变量的声明都将被提升到函数的最顶部,也就是说我们可以先使用后声明,但函数表达式和变量表达式只是将函数或者变量的声明提升到函数顶部,函数表达式和变量的初始化将不被提升

变量提升的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var tmp = new Date();
function f() {
console.log(tmp);//undefined
if(false) {
var tmp='hello';
}
}
//【注意】这里申明提升了,定义的内容并不会提升
//等价于
var tmp = new Date();
function f() {
var tmp;
console.log(tmp);
if(false) {
tmp='hello';
}
}

存在重复声明的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var a = 3;
console.log(a); //3
if(true){
var a = 4; //此处声明会被忽略!!!仅用于赋值!
console.log(a);//4
}
console.log(a); //4
//【注意】在同一作用域用var声明变量多次,后面的var声明会被忽略
//等价于
var a = 3;
console.log(a);//3
if(true){
a = 4;
console.log(a);//4
}
console.log(a);//4

变量和函数同时提升:

1
2
3
4
5
6
7
8
9
//情况一
console.log(a); //[Function: a]
var a = 1;
function a(){};//函数声明形式

//情况二
console.log(a);//undefined
var a = 1;
var a = function(){};//函数表达式形式

情况二就相当于重复声明的例子,容易理解。对于情况一,其等价形式:

1
2
3
var a = function(){};
console.log(a);
a = 1;
  • 函数声明被提升到最顶上;
  • 申明只进行一次,因此后面var a = 1的申明会被忽略。
  • 函数申明的优先级优于变量申明,且函数声明会连带定义一起被提升(这里与变量不同)

块级作用域

ES6新增了let和const命令,可以用来创建块级作用域变量,使用let命令声明的变量只在let命令所在代码块内有效。

使用let声明变量,会将变量的作用域限制在当前代码块中。特点:

  • 变量不会提升到代码块顶部且不允许从外部访问块级作用域内部变量
  • 不允许反复声明
1
2
3
4
5
6
7
8
9
10
11
console.log(a);  //error
let a = 2;
for(let i = 0; i < 3; i++){
console.log(a);
}
console.log(i); //error

function func(){
var a = 1;
let a = 2;//error
}

作用域链

关于编译原理

编译原理

传统编译语言流程:

  1. 分词/词法解析:这个过程会由字符组成的字符串分解成有意义的代码块,这些代码块被称为词法单元(token)。例如:var a = 2;通常被分解为:var、a、=、2、; 。
  2. 解析/语法分析:这个过程将词法单元流(数组)转换成一个由元素逐级嵌套所组成的代表了程序语法结构的树。这个数被抽象为“抽象语法树”(AST)。
  3. 代码生成。将AST转换为可执行的过程被称为代码生成。

JavaScript编译过程不同之处:

  • JavaScript 大部分情况下编译发生在代码执行前的几微秒(甚至更短!)的时间内
  • JavaScript 引擎用尽了各种办法(比如 JIT,可以延 迟编译甚至实施重编译)来保证性能最佳

JavaScript是如何执行的

JavaScript编译过程

  • 核心重点:变量和函数在内的所有声明都会在任何代码被执行前首先被处理。
  • 函数运行的瞬间,创建一个AO (Active Object 活动对象)运行载体。

作用域链是什么?

JavaScript上每一个函数执行时,会先在自己创建的AO上找对应属性值。若找不到则往父函数的AO上找,再找不到则再上一层的AO,直到找到window(全局作用域)。而这一条形成的“AO链” 就是JavaScript中的作用域链。

参考资料

  1. 《你不知道的JavaScript》上卷
  2. 深入理解JavaScript
  3. javascript作用域

Vim基础

发表于 2020-03-11 | 分类于 Linux

VIM

Vim快速入门

Vim模式简介

从vi衍生出来的Vim具有多种模式,这种独特的设计容易使初学者产生混淆。几乎所有的编辑器都会有插入和执行命令两种模式,并且大多数的编辑器使用了与Vim截然不同的方式:命令目录(鼠标或者键盘驱动),组合键(通常通过control键(CTRL)和alt键(ALT)组成)或者鼠标输入。Vim和vi一样,仅仅通过键盘来在这些模式之中切换。这就使得Vim可以不用进行菜单或者鼠标操作,并且最小化组合键的操作。对文字录入员或者程序员可以大大增强速度和效率。

Vim具有6种基本模式和5种派生模式,我们这里只简单介绍下6种基本模式:

  • 普通模式(Normal mode)

在普通模式中,用的编辑器命令,比如移动光标,删除文本等等。这也是Vim启动后的默认模式。这正好和许多新用户期待的操作方式相反(大多数编辑器默认模式为插入模式)。

Vim强大的编辑能来自于其普通模式命令。普通模式命令往往需要一个操作符结尾。例如普通模式命令dd删除当前行,但是第一个”d”的后面可以跟另外的移动命令来代替第二个d,比如用移动到下一行的”j”键就可以删除当前行和下一行。另外还可以指定命令重复次数,2dd(重复dd两次),和dj的效果是一样的。用户学习了各种各样的文本间移动/跳转的命令和其他的普通模式的编辑命令,并且能够灵活组合使用的话,能够比那些没有模式的编辑器更加高效地进行文本编辑。

在普通模式中,有很多方法可以进入插入模式。比较普通的方式是按a(append/追加)键或者i(insert/插入)键。

  • 插入模式(Insert mode)

在这个模式中,大多数按键都会向文本缓冲中插入文本。大多数新用户希望文本编辑器编辑过程中一直保持这个模式。

在插入模式中,可以按ESC键回到普通模式。

  • 可视模式(Visual mode)

这个模式与普通模式比较相似。但是移动命令会扩大高亮的文本区域。高亮区域可以是字符、行或者是一块文本。当执行一个非移动命令时,命令会被执行到这块高亮的区域上。Vim的”文本对象”也能和移动命令一样用在这个模式中。

  • 选择模式(Select mode)

这个模式和无模式编辑器的行为比较相似(Windows标准文本控件的方式)。这个模式中,可以用鼠标或者光标键高亮选择文本,不过输入任何字符的话,Vim会用这个字符替换选择的高亮文本块,并且自动进入插入模式。

  • 命令行模式(Command line mode)

在命令行模式中可以输入会被解释成并执行的文本。例如执行命令(:键),搜索(/和?键)或者过滤命令(!键)。在命令执行之后,Vim返回到命令行模式之前的模式,通常是普通模式。

  • Ex模式(Ex mode)

这和命令行模式比较相似,在使用:visual命令离开Ex模式前,可以一次执行多条命令。

这其中我们常用到就是普通模式、插入模式和命令行模式,本课程也只涉及这三个常用模式的内容

进入vim

使用vim命令进入vim界面

vim后面加上你要打开的已存在的文件名或者不存在(则作为新建文件)的文件名。 打开Xfce终端,输入以下命令

1
$ vim practice_1.txt

直接使用vim也可以打开vim编辑器,但是不会打开任何文件。

1
$ vim

进入命令行模式后输入:e 文件路径 同样可以打开相应文件。

游标移动

在进入vim后,按下i键进入插入模式。在该模式下您可以输入文本信息.

按Esc进入普通模式,在该模式下使用方向键或者h,j,k,l键可以移动游标。

按键 说明
h 左
l 右(小写L)
j 下
k 上
w 移动到下一个单词

进入插入模式

在普通模式下使用下面的键将进入插入模式,并可以从相应的位置开始输入

命令 说明
i 在当前光标处进行编辑
I 在行首插入
A 在行末插入
a 在光标后插入编辑
o 在当前行后插入一个新行
O 在当前行前插入一个新行
cw 替换从光标所在位置后到一个单词结尾的字符

保存文档

命令行模式下保存文档

从普通模式输入:进入命令行模式,输入w回车,保存文档。输入:w 文件名可以将文档另存为其他文件名或存到其它路径下

退出vim

命令行模式下退出vim

从普通模式输入:进入命令行模式,输入wq回车,保存并退出编辑

以下为其它几种退出方式:

命令 说明
:q! 强制退出,不保存
:q 退出
:wq! 强制保存并退出
:w <文件路径> 另存为
:saveas 文件路径 另存为
:x 保存并退出
:wq 保存并退出

普通模式下退出vim

普通模式下输入Shift+zz即可保存退出vim

删除文本

普通模式下删除vim文本信息

进入普通模式,使用下列命令可以进行文本快速删除:

命令 说明
x 删除游标所在的字符
X 删除游标所在前一个字符
Delete 同x
dd 删除整行
dw 删除一个单词(不适用中文)
d$或D 删除至行尾
d^ 删除至行首
dG 删除到文档结尾处
d1G 删至文档首部

除此之外,你还可以在命令之前加上数字,表示一次删除多行,如:

2dd表示一次删除2行

Vim 文档编辑

Vim重复命令

重复执行上次命令

在普通模式下.(小数点)表示重复上一次的命令操作

比如:普通模式下输入x,删除第一个字符,输入.(小数点)会再次删除一个字符,除此之外也可以重复dd的删除操作

执行指令次数相同的命令

进入普通模式输入N,N 表示重复后面的次数,下面来练习:

比如:

  • 输入10x,删除10个连续字符
  • 输入3dd,将会删除3行文本

在普通模式下,你还可以使用dw或者daw(delete a word)删除一个单词,所以你可以很容易的联想到dnw(n替换为相应数字) 表示删除n个单词

游标快速跳转

普通模式下,下列命令可以让光标快速调转到指定位置,我们分别讨论快速实现行间跳转和行内跳转

行间跳转

命令 说明
nG(n Shift+g) 游标移动到第 n 行(如果默认没有显示行号,请先进入命令模式,输入:set nu以显示行号)
gg 游标移动到到第一行
G(Shift+g) 到最后一行

小技巧:你在完成依次跳转后,可以使用 Ctrl+o 快速回到上一次(跳转前)光标所在位置,这个技巧很实用,比如当你在写代码时,忽然想起有个 bug,需要修改,这时候你跳过去改好了,只需要按下 Ctrl+o 就可以回到你之前的位置。vim 中会用很多类似的小技巧就等着你去发掘。

行内跳转

普通模式下使用下列命令在行内按照单词为单位进行跳转

命令 说明
w 到下一个单词的开头
e 到当前单词的结尾
b 到前一个单词的开头
ge 到前一个单词的结尾
0或^ 到行头
$ 到行尾
f<字母> 向后搜索<字母>并跳转到第一个匹配的位置(非常实用)
F<字母> 向前搜索<字母>并跳转到第一个匹配的位置
t<字母> 向后搜索<字母>并跳转到第一个匹配位置之前的一个字母(不常用)
T<字母> 向前搜索<字母>并跳转到第一个匹配位置之后的一个字母(不常用)

操作练习:

  • 在普通模式下,任意跳转到一行,使用 w 跳转到一个单词的开头,然后使用 dw 删除这个单词
  • 在普通模式下,使用 e 跳转到一个单词的结尾,并使用 ~ 将游标所在字母变成大写或小写

复制粘贴和剪切

复制及粘贴文本

  • 普通模式中使用y复制
    • 普通模式中,yy复制游标所在的整行(3yy表示复制3行)
    • 普通模式中,y^ 复制至行首,或y0。不含光标所在处字符。
    • 普通模式中,y$ 复制至行尾。含光标所在处字符。
    • 普通模式中,yw 复制一个单词。
    • 普通模式中,y2w 复制两个单词。
    • 普通模式中,yG 复制至文本末。
    • 普通模式中,y1G 复制至文本开头。
  • 普通模式中使用 p 粘贴
    • 普通模式中,p(小写)代表粘贴至光标后(下)
    • 普通模式中,P(大写)代表粘贴至光标前(上)

剪切及粘贴

其实前面讲得 dd 删除命令就是剪切,你每次 dd 删除文档内容后,便可以使用 p 来粘贴,也这一点可以让我们实现一个很爽快的功能——交换上下行:

ddp ,就这么简单,即实现了快速交换光标所在行与它下面的行

查找替换

字符的替换及撤销(Undo操作)

替换和撤销(Undo)命令

替换和Undo命令都是针对普通模式下的操作

命令 说明
r+<待替换字母> 将游标所在字母替换为指定字母
R 连续替换,直到按下Esc
cc 替换整行,即删除游标所在行,并进入插入模式
cw 替换一个单词,即删除一个单词,并进入插入模式
C(大写) 替换游标以后至行末
~ 反转游标所在字母大小写
u{n} 撤销一次或n次操作
U(大写) 撤销当前行的所有修改
Ctrl+r redo,即撤销undo的操作

快速缩进

使用命令进行快速调整缩进操作

缩进操作均在普通模式下有效

打开文件进行编辑

1
$ vim protocols
  • 普通模式下输入15G,跳转到15行
  • 普通模式下输入>> 整行将向右缩进(使用,用于格式化代码超爽)
  • 普通模式下输入<< 整行向左回退
  • 普通模式下输入:进入命令行模式下对shiftwidth值进行设置可以控制缩进和回退的字符数

shiftwidth命令

shiftwidth命令是指上一节>>命令产生的缩进(可以简写成sw) 普通模式下输入:进入命令行模式下对shiftwidth值进行设置可以控制缩进和回退的字符数 获取目前的设定值

1
:set shiftwidth?

设置缩进为10个字符

1
:set shiftwidth=10

输入 ESC 回到普通模式,再次尝试 >> 看缩进量是否变化

调整文本位置

命令行模式下输入:ce(center)命令使本行内容居中

1
:ce

命令行模式下输入:ri(right)命令使本行文本靠右

1
:ri

命令行模式下输入:le(left)命令使本行内容靠左

1
:le

查找

快速查找

普通模式下输入 / 然后键入需要查找的字符串 按回车后就会进行查找。 ? 与/ 功能相同,只不过 ? 是向上而 / 是向下查找。 进入查找之后,输入n 和 N 可以继续查找。 n是查找下一个内容,N查找上一个内容。

快速查找练习

使用 vim 打开文件进行编辑(搜索高亮需要在配置文件 .vimrc 中设置 set hls ,实验环境中已经设置好了)

1
$ vim protocols
  • 普通模式下输入/icmp然后回车即可查找字符串 icmp
  • 普通模式下输入n查找下一个 icmp
  • 普通模式下输入?tcp向上查找字符串 tcp
  • 普通模式下输入N查找上一个出现的 tcp
  • 命令行模式下输入 noh 然后回车即可取消搜索

高级查找

  • 普通模式下输入\*寻找游标所在处的单词
  • 普通模式下输入\#同上,但 \# 是向前(上)找,\*则是向后(下)找
  • 普通模式下输入g\*同\* ,但部分符合该单词即可
  • 普通模式下输入g\#同\# ,但部分符合该单词即可

以上查找n,N 的继续查找命令依然可以用

高级功能入门

多文件编辑

使用vim编辑多个文件

编辑多个文件有两种形式,一种是在进入vim前使用的参数就是多个文件。另一种就是进入vim后再编辑其他的文件。 同时创建两个新文件并编辑

1
$ vim 1.txt 2.txt

默认进入1.txt文件的编辑界面

  • 命令行模式下输入 :n 编辑 2.txt 文件,可以加 ! 即 :n! 强制切换,之前一个文件的输入没有保存,仅仅切换到另一个文件
  • 命令行模式下输入 :N 编辑 1.txt 文件,可以加 ! 即 :N! 强制切换,之前文件内的输入没有保存,仅仅是切换到另一个文件

进入vim后打开新文件

  • 命令行模式下输入:e 3.txt 打开新文件3.txt
  • 命令行模式下输入:e# 回到前一个文件
  • 命令行模式下输入:ls可以列出以前编辑过的文档
  • 命令行模式下输入:b 2.txt(或者编号)可以直接进入文件2.txt编辑
  • 命令行模式下输入:bd 2.txt(或者编号)可以删除以前编辑过的列表中的文件项目
  • 命令行模式下输入:e! 4.txt,新打开文件4.txt,放弃正在编辑的文件
  • 命令行模式下输入:f 显示正在编辑的文件名
  • 命令行模式下输入:f new.txt,改变正在编辑的文件名字为new.txt

恢复文件

如果因为断电等原因造成文档没有保存,可以采用恢复方式,vim -r进入文档后,输入:ewcover 1.txt来恢复

1
$ vim -r 1.txt

可视模式

可视模式命令简介

  • 在普通模式下输入 v(小写),进入字符选择模式,就可以移动光标,光标走过的地方就会选取。再次按下v后就会取消选取。
  • 在普通模式下输入 Shift+v(小写),进入行选择模式,按下V之后就会把整行选取,您可以上下移动光标选更多的行,同样,再按一次 Shift+v 就可以取消选取。
  • 在普通模式下输入 Ctrl+v(小写),这是区域选择模式,可以进行矩形区域选择,再按一次 Ctrl+v 取消选取。
  • 在可视模式下输入 d 删除选取区域内容
  • 在可视模式下输入y复制选取区域内容

可视模式命令练习

拷贝练习文件到当前目录

1
$ cp /etc/protocols .

打开练习文件

1
$ vim protocols
  • 在普通模式下9G跳转到第9行,输入Shift+v(小写V),进入可视模式进行行选择,选中5行,按下>>缩进,将5行整体缩进一个shiftwidth
  • 在普通模式下输入 Ctrl+v(小写V),进入可视模式进行矩形区域选择,选中第一列字符然后x删除整列

视窗操作

视窗操作简介

vim 可以在一个界面里打开多个窗口进行编辑,这些编辑窗口称为 vim 的视窗。 打开方法有很多种,例如:可以使用在命令行模式下输入 :new 打开一个新的 vim 视窗,并进入视窗编辑一个新文件(普通模式下输入 Ctrl+w也可以),除了 :new 命令,下述列举的多种方法也可以在命令模式或普通模式下打开新的视窗:

注意:快捷键可能会与浏览器的快捷键冲突,可换为 IE 浏览器进行实验或者在浏览器设置里禁用浏览器快捷键。

  • 命令行模式下输入:sp 1.txt 打开新的水平分屏视窗来编辑1.txt
  • 命令行模式下输入:vsp 2.txt 打开新的垂直分屏视窗来编辑2.txt
  • 普通模式下Ctrl+w s 将当前窗口分割成两个水平的窗口
  • 普通模式下Ctrl+w v 将当前窗口分割成两个垂直的窗口
  • 普通模式下Ctrl+w q 即 :q 结束分割出来的视窗。如果在新视窗中有输入需要使用强制符!即:q!
  • 普通模式下Ctrl+w o 打开一个视窗并且隐藏之前的所有视窗
  • 普通模式下Ctrl+w j 移至下面视窗
  • 普通模式下Ctrl+w k 移至上面视窗
  • 普通模式下Ctrl+w h 移至左边视窗
  • 普通模式下Ctrl+w l 移至右边视窗
  • 普通模式下Ctrl+w J 将当前视窗移至下面
  • 普通模式下Ctrl+w K 将当前视窗移至上面
  • 普通模式下Ctrl+w H 将当前视窗移至左边
  • 普通模式下Ctrl+w L 将当前视窗移至右边
  • 普通模式下Ctrl+w - 减小视窗的高度
  • 普通模式下Ctrl+w + 增加视窗的高度

视窗操作练习

打开练习文件

1
$ vim 1.txt
  • 命令行模式下输入:new 打开一个新的vim视窗
  • 命令行模式下输入:vsp 2.txt 打开新的横向视窗来编辑2.txt
  • 命令行模式下输入:vsp 3.txt 打开新的横向视窗来编辑3.txt
  • 如果使用非chrome浏览器可以使用Ctrl+w进行视窗间的跳转
  • 分别在不同视窗的命令行模式下输入:q!退出多视窗编辑

文档加密

创建加密文档

1
$ vim -x file1

输入您的密码 确认密码 这样在下一次打开时,vim就会要求你输入密码

在vim执行外部命令

在命令行模式中输入!可以执行外部的shell命令

  • :!ls 用于显示当前目录的内容
  • :!rm FILENAME用于删除名为 FILENAME 的文件
  • :w FILENAME可将当前 VIM 中正在编辑的文件另存为 FILENAME 文件

帮助系统

vim中的查看帮助

  • 普通模式下按F1打开vim自己预设的帮助文档
  • 命令行模式下输入:h shiftwidth 打开名为shiftwidth的帮助文件
  • 命令行模式下输入:ver 显示版本及参数

功能设定

vim的功能设定

可以在编辑文件的时候进行功能设定,如命令行模式下输入:set nu(显示行数),设定值退出vim后不会保存。要永久保存配置需要修改vim配置文件。 vim的配置文件~/.vimrc(实验楼环境中配置文件在/etc/vim/vimrc),可以打开文件进行修改,不过务必小心不要影响vim正常使用

获取目前的设定

  • 命令行模式下输入:set或者:se显示所有修改过的配置
  • 命令行模式下输入:set all 显示所有的设定值
  • 命令行模式下输入:set option? 显示option的设定值
  • 命令行模式下输入:set nooption 取消当前设定值

set功能的说明

  • 命令行模式下输入:set autoindent(ai) 设置自动缩进
  • 命令行模式下输入:set autowrite(aw) 设置自动存档,默认未打开
  • 命令行模式下输入:set background=dark或light,设置背景风格
  • 命令行模式下输入:set backup(bk) 设置自动备份,默认未打开
  • 命令行模式下输入: set cindent(cin) 设置C语言风格缩进

锋利的jQuery笔记

发表于 2019-07-25 | 分类于 前端学习

锋利的jQuery

第一章 认识jQuery

  • jQuery简介优势,JavaScript的缺点

  • 程序中的$符号是jQuery的一个简写

  • window.onload与$(document).ready()的区别

  • jQuery代码风格

  • jQuery对象和DOM对象的介绍

    1.jQuery转换为DOM对象

    (1)jQuery是一个类数组对象,可以通过[index]的方法得到对应的DOM对象

    1
    2
    var $cr = $("#cr");
    var cr = $cr[0];

    (2)这种方法是jQuery本身提供的,通过get(index)方法得到对应的DOM对象

    1
    2
    var &cr = $("#cr");
    var cr = $cr.get(0);

    2.DOM对象转成jQuery对象

    对于一个DOM对象,只需要用$()把DOM对象包装起来,就可以获得一个jQuery对象了

    1
    2
    var cr = document.getElementById("cr");
    var $sr = $(cr);

    【注意】:DOM对象才能使用都DOM中的方法,jQuery对象不可以使用DOM中的方法。

  • 解决jQuery和其它库的冲突

    • jQuery.noConflict()方法
    • jQuery库在其它库之前导入
    • jQuery库在其它库之后导入

第二章 jQuery选择器

  • CSS的选择器

  • CSS选择器找到元素后是添加样式,而jQuery选择器找到元素后是添加行为;jQuery的行为准则都必须在获取到元素之后才能生效。

  • jQuery选择器的优势(简洁的写法、支持CSS1到CSS3的选择器、完善的处理机制)

  • jQuery选择器分为基本选择器、层次选择器、过滤选择器和表单选择器

  • 基本选择器

    选择器 描述 返回
    #id 根据给定的id匹配一个元素 单个元素
    .class 根据给定的类名匹配元素 集合元素
    element 根据匹配的元素名匹配元素 集合元素
    * 匹配所有元素 集合元素
    selector1, selector2,… 将每一个选择器匹配到的元素合并后一起返回 集合元素
  • 层次选择器

    选择器 描述 返回
    $(“ancestor descendant”) 选取ancestor元素里的所有后代元素 集合元素
    $(“parent>child”) 选取parent元素下的子元素 集合元素
    $(“prev+next”) 选取紧接在perv元素后的next元素 集合元素
    $(“prev~siblings”) 选取prev元素之后的所有siblings元素 集合元素
  • 过滤选择器包括:基本过滤选择器,内容过滤选择器、可见性过滤选择器、属性过滤选择器、子元素过滤选择器、表单对象属性过滤选择器

  • 基本过滤选

    选择器 描述 返回
    :first 选取第一个元素 单个元素
    :last 选取最后一个元素 单个元素
    :not(selector) 去除所有与给定选择器匹配的元素 集合元素
    :even 选取索引是偶数的元素 集合元素
    :odd 选取索引是奇数的元素 集合元素
    :eq(index) 选取索引等于index的元素 单个元素
    :gt(index) 选取索引大于index的元素 集合元素
    :lt(index) 选取索引小于index的元素 集合元素
    :header 选取所有的标题元素 集合元素
    :animated 选取当前正在执行动画的所有元素 集合元素
    :focus 选取当前获得焦点的元素 集合元素
  • 内容过滤选择器

    选择器 描述 返回
    :contains(text) 选取含有文本内容为“text”的元素 集合元素
    :empty 选取不包含子元素或者文本的空元素 集合元素
    :has(selector) 选取含有选择器所匹配的元素的元素 集合元素
    :parent 选取含有子元素或者文本的元素 集合元素
  • 可见性过滤选择器

    选择器 描述 返回
    :hidden 选取所有不可见的元素 集合元素
    :visible 选取所有可见的元素 集合元素
  • 属性过滤选择器

    选择器 描述 返回
    [attribute] 选取拥有此属性的元素 集合元素
    [attribute=value] 选取属性值为value的元素 集合元素
    [attribute!=value] 选取属性值不等于value的元素 集合元素
    [attribute^=value] 选取属性值以value开头的元素 集合元素
    [attribute$=value] value结尾 集合元素
    [attribute*=value] 含有value 集合元素
    [attribute|=value] 选取属性等于给定字符串或以该字符串为前缀 集合元素
    [attribute~=value] 选取属性用空格分隔的值中包含一个给定值的元素 集合元素
    [attribute1][attribute2][attributeN] 用属性选择器合并一个复合属性选择器,满足多个条件。每选择一次,缩小一次范围 集合元素
  • 子元素过滤选择器

    选择器 描述 返回
    :nth-child(index/even/odd/equation) 选取每个父元素下的第index个子元素或者奇偶元素(下标从1开始) 集合元素
    :first-child 选取每个父元素第一个子元素 集合元素
    :last-child 选取每个服元素最后一个子元素 集合元素
    :only-child 唯一元素 集合元素
  • 表单对象属性过滤选择器

    选择器 描述 返回
    :enabled 选取所有可用的元素 集合元素
    :disabled 选取所有不可用的元素 集合元素
    :checked 选取所有被选中的元素(单选复选框) 集合元素
    :selected 选取所有被选中的选项元素(下拉元素) 集合元素
  • 表单选择器

    选择器 描述 返回
    :input 选择所有的、 集合元素
    :text 选取所有的单行文本框 集合元素
    :passward 密码框 集合元素
    :radio 单选框 集合元素
    :checkbox 多选框 集合元素
    :submit 提交按钮 集合元素
    :image 图像按钮 集合元素
    :reset 重置按钮 集合元素
    :button 所有的按钮 集合元素
    :file 所有的上传域 集合元素
    :hidden 所有不可见元素 集合元素
  • 选择器中的一些注意事项

    • 选择器中含有“.”、“#”、“(”、或“[”等特殊字符
    • 选择器的@符号问题
    • 选择器中含有空格的注意事项
  • 其它选择器

第三章 jQuery中的DOM操作

  • DOM的分类(DOM Core、HTML-DOM、CSS-DOM)

  • 查找节点

    查找元素节点(通过选择器来完成)、查找属性节点(attr()方法来获取它的各种属性的值)

    1
    2
    var $li = $("ul :eq(1)); //获取<ul>里面的第二个<li>标签
    var text = $("para").attr("title"); //获取属性title
  • 创建节点

    创建元素节点(工厂模式$())、创建文本节点、创建属性节点

    1
    2
    3
    var $li_1 = $("<li></li>") //创建了一个<li>元素
    var $li_2 = $("<li>香蕉<li>"); //创造了一个文本节点
    var $li_3 = $("<li title="香蕉">香蕉</li>")//创建了一个属性节点
  • 插入、移动节点

    append(),appendTo() ,prepend(),prependTo(),after(),insertAfter() ,before() ,insertBefore()

    方法 描述
    append() 向每个匹配元素内部追加内容
    appendTo() 颠倒了append()方法
    prepend() 向每个匹配元素内部前置内容
    prependTo() 颠倒了prepend()
    after() 在每个匹配元素之后插入内容
    insertAfter() 颠倒了after()
    before() 在每个元素之前插入内容
    insertBefore() 颠倒before()
  • 删除节点

    remove()方法、detach()方法、empty()方法

    remove()方法:当某个节点用remove()方法删除后,该节点包含的所有后代节点将同时被删除。这个方法的返回值是一个指向已被删除的节点的引用,因此可以在以后再使用这些元素。

    detach()方法:这个方法和remove()一样,也是从DOM中去除所有匹配元素,但这个方法不会把匹配的元素从jQuery对象中删除,因而可以在将来再使用这些匹配的元素,与remove()方法不同的是,所有绑定的事件、附加的数据等都会保留下来。

    empty()方法:严格来说empty()方法并不是删除节点,而是清空节点,它能清空元素中的所有后代节点。

  • 复制节点

    clone()方法(注意深复制和浅复制)

    clone(): 复制节点后,被复制的新元素并不具有任何行为。

    clone(true): 复制元素的同时复制元素中所绑定的事件。

  • 替换节点

    replaceWith()方法和replaceAll()方法

    replaceWith()方法的作用是将所匹配的元素都替换成指定的HTML或者DOM元素。

    replaceAll()是replaceWith()的颠倒方法。

    如果在替换之前,已经为元素绑定事件,替换后原先绑定的事件将会与被替换的元素一起消失,需要在新元素上重新绑定新的事件。

  • 包裹节点

    wrap()方法、wrapAll()方法、wrapInner()方法

    将某个节点用其它标记包裹起来。

    1. wrap()
    1
    2
    $("strong").wrap("<b></b>"); //用<b>标签把<strong>元素包裹起来
    //结果:<b><strong>你好</strong></b>

    2.wrapAll()。该方法会将所有匹配的元素用一个元素包裹起来,不同于wrap()方法,wrap()方法是把所有的元素进行单独的包裹。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /*
    html代码:
    <strong>haha</strong>
    <strong>xixi</strong>
    */
    $("strong").wrap("<b></b>");
    //结果:
    //<b><strong>haha</strong></b>
    //<b><strong>xixi</strong></b>
    $("strong").wrapAll("<b></b>");
    //结果:
    //<b>
    //<strong>haha</strong>
    //<strong>xixi</strong>
    //</b>

    //如果被包裹的多个元素间有其他元素,其他元素会被放到包裹元素之后

    3.wrapInner()方法,该方法将每一个匹配的元素的子内容(包括文本节点)用其他结构化的标记包裹起来。

    1
    2
    $("strong").wrapInner("<b></b>");
    //<strong><b>哈哈</b></storng>
  • 属性操作

    获取和设置属性(attr()方法)、删除属性(removeAttr()方法)

    1
    2
    3
    4
    $("P").attr("title", "haha");
    $("P").atrr("title":"jaja", "name":"test");

    &("P").removeAttr("title");
  • 样式操作

    获取和设置样式(attr()方法)、追加样式(addClass()方法)【注意attr()和addClass()的区别】、移除样式(removeClass()方法)、切换样式(toggle()方法和toggleClass()方法)、判断是否含有某个样式(hasClass()方法)

    1
    2
    3
    $("p").addClass("another"); //给<p>元素追加“another”类
    $("p").removeClass("another"); //移除类;若不今添加参数,则将class的值全部清除
    $("p").hasClass("another");//判断元素中是否含有某个类,如果有则返回true
    1
    2
    3
    4
    5
    6
    7
    8
    $toggleBtn.toggle(function(){
    //显示元素 代码③
    },function(){
    //隐藏元素 代码④
    })
    /*toggle()方法在此处的作用是交替执行代码③和代码④两个函数,如果元素原来是显示的,则隐藏它;反之,显示*/

    $("p").toggleClass("another"); //重复切换类名“another"
  • 设置和获取HTML、文本和值

    html()方法、text()方法、val()方法

    html():类似于JavaScript中的innerHTML属性,可以用来读取或者设置某个元素中的HTML内容。

    text():类似于JavaScript中的innerText属性,可以用来读取或者设置某个元素中的文本内容。

    val():类似于JavaScript中的value属性,可以用来设置和获取元素的值。无论是文本框、下拉列表还是单选框,它都可以返回元素的值。如果元素为多选,则返回一个包含所有选择的值的数组。

  • 遍历节点

    children()方法、next()方法,prev()方法,siblings()方法、closest()方法、parent(),parents(),closest()的区别

    children():取得匹配元素的所有子元素集合。(只考虑子元素而不考虑其他后代元素)

    next():取得匹配元素后面紧邻的同辈元素。

    prev():取得匹配元素前面紧邻的同辈元素。

    siblings():取得所匹配元素前后所有的同辈元素。

    closest():取得最近的匹配元素,首先检查当前元素是否匹配,如果匹配则直接返回元素本身。如果不匹配则向上查找父元素,逐级向上直到找到匹配选择器的元素如果什么都没找到,则返回一个空的jQuery对象。

    parent():获得集合中每个元素的父级元素。

    parents():获得集合中每个元素的祖先元素。

  • CSS-DOM操作

    css()方法、height()方法、width()方法、offset()方法、position()方法、scrollTop()方法和scrollLeft()方法

    css() : 可以直接利用css()方法设置某个元素的单个样式,也可以同时设置多个样式属性。

    offset():获取在当前视窗的相对偏移,其中返回的对象包含两个属性,即top和left。

    1
    2
    3
    var offset = $("p").offset();
    var left = offset.left;
    var top = offset.top;

position():获取元素相对于最近的一个position样式属性设置为relative或者absolute的祖父节点的相对偏移,包含两个属性,即top和left。

scrollTop()和scrollLeft()方法:获取元素的滚动条距顶端的距离和距左端的距离。也可以为这两个方法指定一个参数,控制元素的滚动条滚动到指定位置。

第四章 jQuery的事件和动画

jQuery中的事件

  • $(document).ready()方法和window.onload方法的异同点

    • 执行时机
    • 多次使用
    • 间歇方式
  • load()方法($(window).load(function(){ }))

  • 事件绑定

    • 在文档装载完成后,如果打算为元素绑定事件来完成某些操作,可以使用bind()方法来对匹配元素进行特定事件的绑定。
    • bind()方法的使用
    • 与ready()方法一样,bind()方法也可以多次调用。
    • is()方法
    • 简写绑定事件
  • 合成事件

    • hover()方法(jQuery自定义的方法,用于模拟光标悬停事件)的使用和注意事项。
    • toggle()方法(用于模拟鼠标连续单击事件)的作用和使用。
  • 事件冒泡

    • 什么是事件冒泡以及事件冒泡引发的问题
    • 事件对象(①jQuery进行了必要的扩展和封装,从而使得在任何浏览器中都能很轻松的获得事件对象以及事件对象的一些属性 ②在程序中使用事件对象只需要为函数添加一个参数③这个事件对象只有事件处理函数才能访问到。事件处理函数执行完毕后,事件对象就被销毁)
    • stopPropagation()方法—阻止事件冒泡
    • preventDefault()方法—阻止元素的默认行为
    • 如果想同时对事件对象停止冒泡和默认行为,可以在事件处理函数中返回false。这是对在事件对象上同时调用stopPropagation()方法和preventDefault()方法的一种简写方式。
    • jQuery不支持事件捕获。
  • 事件对象的属性

    • event.type — 获取到事件的类型
    • event.stopPropagation()方法 — 阻止事件冒泡
    • event.preventDefault()方法 — 阻止默认行为
    • event.target — 获取到触发事件的元素
    • event.relatedTarget
    • event.pageX 和 event.pageY — 获取到光标相对于页面x坐标和y坐标
    • event.which — 在鼠标单击事件中获取到鼠标的左、中、右键;在键盘事件中获取键盘的按键
    • event.metaKey — 在键盘事件中获取<ctrl>键
  • 移除事件

    • 不仅可以为同一个元素绑定多个事件,也可以为多个元素绑定同一个事件。
    • unbind()方法的使用与说明
    • one()方法 — one()方法可以为元素绑定处理函数,当处理函数触发一次后,立即被删除。即在每个对象上,事件处理函数只会被执行一次。
  • 模拟事件

    • trigger()方法

      ①可以完成模拟操作(常用模拟)

      ②不仅能触发浏览器支持的具有相同名称的事件,也可以触发自定义的事件(触发自定义事件)

      ③该方法有两个参数,第一个参数是要触发的时间类型,第二个参数是要传递给事件处理函数的附加数据,以数组形式传递。(传递数据)

      ④trigger()方法触发后,会执行浏览器默认操作。(执行默认操作)

      ⑤如果只想触发事件而不想执行浏览器的默认操作,可以使用triggerHandler()方法。

  • 其它用法

    前面已经介绍,bind()方法不仅能为元素绑定浏览器支持的具有相同名称的事件,也可以绑定自定义事件。

    • 绑定多个事件类型
    • 添加事件命名空间,便于管理
    • 相同事件名称,不同命名空间执行方法

jQuery中的动画

  • show()方法和hide()方法

    • 在不带参数的情况下,相当于css("display", "none/block/inline")
    • 【注意】:hide()方法在将“内容”的display属性值设为“none”之前,会记住原先的display属性值。当调用show()方法时,就会根据hide()方法记住的display属性值来显示元素。
    • 可以为hide()和show()方法指定一个参数,比如“slow”,“normal”,“fast”或数值。这样就会产生动画效果。
    • hide(600)方法会同时减少“内容”的高度、宽度和不透明度,直至这三个属性的值都为0,最后设置该元素的CSS规则为“display:none";show(500)方法则会从上打下增加“内容”的高度,从左到右增加“内容”的宽度,同时增加“内容”的不透明度,直至内容完全显示。
  • fadeIn()方法和fadeOut()方法

    • 与show()方法不同,fadeIn()方法和fadeOut()方法只改变元素的不透明度。
    • fadeOut()方法会在指定的一段时间内降低元素的不透明度,直到元素完全消失(”display:none“)。fadeIn()方法与之相反。
  • slideUp()方法和slideDown()方法

    • 这两个方法会改变元素的高度
    • 如果一个元素的display属性值为“none”,当调用slideDown()方法时,这个元素将由上到下延伸显示。slideUp()与之想反。
  • 自定义动画方法animate()

    • animate()的语法
    • 自定义简单动画,累加、累减动画,多重动画(同时执行多个动画、按顺序执行多个动画),综合动画
    • animate()方法可以用来代替其他所有的动画方法
  • 动画回调函数

    • 如果想在最后一步切换元素的样式,可以使用回调函数
    • css()方法并不会加入到动画队列中,而是立即执行,可以使用回调函数(callback)对非动画方法实现排队。只要把css()方法写在最后一个动画的回调函数里即可
  • 停止动画和判断是否处于动画状态

    • 停止元素的动画(stop()方法)

      ①语法:stop([clearQueue],[gotoEnd]); 参数都可选,均为布尔值。clearQueue代表是否清空未执行完的动画队列;gotoEnd代表是否直接将正在执行的动画跳转到末状态。

      ②直接使用stop()方法,则会立即停止当前正在进行的动画,如果接下来还有动画等待继续进行,则以当前状态开始接下来的动画。

    • 判断元素是否处于动画状态

      在使用animate()方法的时候,要避免动画积累而导致的动画与用户的行为不一致。当用户快速在某个元素上执行animate()动画时,就会出现动画积累。解决方法是判断元素是否正处于动画状态,如果元素不处于动画状态,才为元素添加新的动画,否则不添加。

      1
      2
      3
      if(!$(element).is(":animated")){ //判断元素是否处于动画状态
      //如果当前没有进行动画,则添加新动画
      }
  • 延迟动画

    如果想对动画进行延迟操作,可以使用delay()方法

  • 其它动画方法

    • toggle()方法 — 可以切换元素的可见状态。
    • slideTaggle()方法 — 通过高度变化来切换匹配元素的可见性。
    • fadeTo()方法 — 可以把元素的不透明度以渐进的方式调整到指定的值。
    • fadeToggle()方法 — 通过不透明度变化来匹配元素的可见性。
  • 动画队列

    • 一组元素上的动画效果
      • 当在一个animate()方法中应用多个属性时,动画是同时发生的
      • 当以链式的写法应用动画方法时,动画是按照顺序发生的(除非queue选项值为false)
    • 多组元素上的动画效果
      • 默认情况下,动画都是同时发生的
      • 当以回调的形式应用动画方式的时(包括动画的回调函数和queue()方法的回调函数),动画是按照回调的顺序发生的。

第五章 jQuery对表单、表格的操作及更多应用

  • 表单应用

    • 表单的组成部分(表单标签、表单域、表单按钮)
    • 单行文本框的应用
    • 多行文本框的应用(高度变化、滚动条高度变化)
    • 复选框应用
    • 下拉框应用
    • 表单验证
  • 表格应用

    • 表格变色(普通的隔行变色、单选框控制表格行高亮、复选框控制表格行高亮)
    • 表格展开关闭
    • 表格内容筛选
  • 其他应用

    • 网页字体大小
    • 网页选项卡
    • 网页换肤

第六章 jQuery与Ajax的应用

part 1

  • Ajax的优势和不足
  • Ajax的XMLHttpRequest对象
  • ==原生JavaScript操作Ajax的步骤==

part 2 jQuery中的Ajax

jQuery对Ajax操作进行了封装,在jQuery中$.ajax()方法属于最底层的方法,第2层是load()、$.get()、$.post方法,第3层是$.getScript()和$.getJSON()方法。

  1. load()方法

    • 载入HTML文档

      load()方法能载入远程HTML代码并插入DOM中。

      结构:load(url [,data] [, callback])

      url – 请求HTML页面的URL地址

      data(可选) — 发送至服务器的key/value数据

      callback(可选) — 请求完成时的回调函数,无论请求成功或失败

    • 筛选载入的HTML文档

      通过为URL参数指定选择符,load()方法的URL参数语法结构是“url selector”

    • 传递方式

      load()方法的传递方式根据参数data来自动指定。如果没有参数传递,则采用GET方式传递;反之,则会自动转换为POST方式。

    • 回调函数

      对于必须在加载完成后才能继续的操作,load()方法提供了回调函数(callback),该函数有3个参数,分别代表请求返回的内容、请求状态和XMLHttpRequest对象

  2. $.get()方法和$.post()方法

    load()方法通常用来从web服务器上获取静态的数据文件,然而这并不能体现Ajax的全部价值。在项目中,如果需要传递一些参数给服务器中的页面,那么可以使用$.get()或者$.post()方法.

    【注意】:$.get()方法和$.post()方法是jQuery中的全局函数,而在此之前讲的jQuery方法都是对jQuery对象进行操作的。

    • $.get()方法

      该方法使用GET方式来进行异步请求

      结构:$.get(url [, data] [, callback] [, type])

      url — 请求的HTML页的URL

      data(可选)— 发送至服务器的key/value数据会作为 QueryString附加到请求URL中

      callback(可选)— 载入成功时回调函数(只有当Response的返回状态是success才调用该方法)自动将请求结果和状态传递给该方法

      type(可选)— 服务器返回内容的格式,包括xml, html, script, json, text 和 _default

      该方法的回调函数只有两个参数。

    • $.post()方法

      $.post()和$.get()方法的结构和使用方式都相同,不过它们之间仍有一下区别:

      ①GET请求会将参数跟在URL后进行传递,而POST请求则是作为HTTP消息的实体内容发送给Web服务器。当然,在Ajax请求中,这种区别对用户是不可见的。

      ②GET方式对传输的数据有大小限制(通常不能大于2KB),而使用POST方式传递的数据量要比GET方式大得多(理论上不受限制)

      ③GET方式请求的数据会被浏览器缓存起来,因此其他人就可以从浏览器的历史记录中读取到这些数据,例如账号密码等。在某种情况下,GET方式会带来严重的安全性问题,而POST方式相对来说就可以避免这些问题。

      ④GET方式和POST方式传递的数据在服务端的获取也不相同。在PHP中,GET方式可以用$_GET[]获取,而POST方式可以用$_POST[]获取。两种方式都可以通过$_REQUEST[]来获取

  3. $.getScript()方法和$.getJson()方法

    • $.getScript()`

    jQuery提供了$.getScript()方法来直接加载.js文件,与加载一个HTML片段一样简单方便,并且不需要对JavaScript文件进行处理,JavaScript文件会自动执行。

    1
    2
    3
    4
    5
    $(function(){
    $("#send").click(function(){
    $.getScript("test.js");
    });
    })

与其他Ajax方法一样,$.getScript()方法也有回调函数,他会在 JavaScript文件成功载入后运行

  • $.getJSON()`

    ​ $.getJSON()方法用于加载JSON文件,与$.getScript()方法的使用方法相同。

    jQuery提供了回调函数,在回调函数里处理返回的数
  • $.each()`方法

    $.each()方法不同于jQuery对象的each()方法,它是一个全局函数,不操作jQuery对象,而是以一个数组或对象作为第一个参数,以一个回调函数作为第二个参数。回调函数拥有两个参数,第一个为对象的成员或数组的索引,第二个为对应变量或内容。

  1. $.ajax()方法

part 3 序列化元素

  1. serialize()方法
  2. serializeArray()方法
  3. $.param()方法

第九章 jQuery Mobile

  • HTML 5的简介

  • jQuery Mobile简介以及它的主要特性

  • jQuery的使用

    • 下载
    • 建议在页面中使用HTML 5标准的页面声明和标签,因为移动设备浏览器对HTML 5的支持程度要远远优于PC设备
    • 构建HTML模板,引入框架
  • data-role属性

  • data-inset属性

  • data-theme属性

  • 其他的框架

  • 例子:

    1
    2
    3
    4
    5
    <ul data-role="listview" data-inset="true" data-theme="e">
    <li><a href="#">Acura</a></li>
    <li><a href="#">Audi</a></li>
    <li><a href="#">BMW</a></li>
    </ul>

前端知识点

发表于 2019-07-24 | 分类于 前端学习

前端知识点

HTML&&CSS

  • 01.html5的SEO优化
  • 02.有趣的空格
  • 03.Html和xhtml的区别
  • 04.盒子模型
  • [05.css sprite](./HTML/04.CSS Sprite)
  • 06.position属性值absolute和relative的区别
  • 07.css选择器
  • 08.css兼容性问题
  • 09.css响应式布局
  • 10.css3实现圆角
  • 11.css3实现至下而上的弹框
  • 12.px、em、rem的区别
  • 13.css盒子模型、bfc
  • 14.元素的水平垂直居中方法
  • 15.Css 渐变
  • 16.display:none和visibility:hidden
  • 17.css优化
  • 18.link和@import区别
  • [19.描述z index和层叠上下文](./CSS/24.描述z index和层叠上下文)
  • 20.css动画与js动画比较
  • 21.负margin的使用
  • [22.有趣的h5api:page visibility api](./HTML/05.有趣的h5api:page visibility api)
  • 23.placeholder的使用及其兼容方法
  • [24.响应式图片 srcset和 picture 的使用](./HTML/响应式图片 srcset和 picture 的使用)
  • 25.display的值与其用法
  • [26.em rem px 区别](./CSS/26.px em rem 区别)
  • [27.flex 布局](./HTML/20.flex 布局)
  • [28.grid 布局](./HTML/grid 布局)
  • 29.伪类
  • 30.页面适配
  • 31.伪元素

JS

  • 03.es5在es3上增加的内容
  • 04.es6中的promise解决异步编程
  • [06.DOM Ready](./js/06.dom ready)
  • 07.js简单动画
  • 08.js基本数据类型和引用类型
  • 09.js获取元素节点的方法
  • 10.如何判断两个对象相等
  • 11.原生js实现jq的事件绑定
  • [12.原生js实现jq的on,attr方法](./js/12.原生js实现jquery的on, attr方法)
  • [13.js实现链表](./js/13. js实现链表)
  • 14.事件委托&&事件流&&事件处理
  • 16.事件模型
  • 17.如何用js实现图片轮播
  • 18.DOM优化
  • 19.js面向对象的三大特征
  • 20.js对象的创建方法
  • 21.如何实现深拷贝
  • 22.js对象
  • 23.js如何实现私有
  • 25.js实现div拖拽
  • 26.js在方法的实例对象上修改方法原型上的属性和方法
  • 28.倒计时实现、计时器延迟问题和效率
  • [29.in的奇妙应用](./js/29. in 的奇妙应用)
  • 30.匿名函数
  • 31.如何实现千位分隔符
  • 32.理解js的闭包
  • 33.半透明图片移上去不透明及对鼠标快速移入移出的处理
  • 34.执行环境与作用域
  • 35.重载
  • 38.this的指向即特殊情况&call()和apply()的区别
  • 41.let与var的区别
  • 42.移动端适配
  • 43.注册重复问题
  • 44.海量数据处理问题
  • [48.异步加载](./js/48. 异步加载)
  • 50.有关变量声明提升的有意思的代码
  • 51.移动端300ms点击延迟
  • 52.箭头函数和普通函数的区别
  • 53.原型链
  • 54.JS垃圾回收机制
  • 56.什么是伪数组和如何将伪数组转化为数组
  • 57.深入理解定时器:setTimeout与setInterval
  • 58.网站性能优化
  • 59.Domcontentloaded和load
  • 60.执行上下文
  • 61.详解HTTPS和HTTP
  • 62.querySelector与getElementBy系列方法区别
  • 63.call与apply的区别
  • 64.Js和jq获取元素位置
  • [65.ARRAY 常用方法](./js/ARRAY 常用方法)
  • 66.函数防抖
  • 67.函数节流
  • 68.new与create的区别
  • 69.Jsonp原理
  • [70.cookie 和 session的区别](./js/70.cookie 和 session的区别)
  • 80.模块化
  • 81.匿名函数的使用实例
  • [82.string常用方法](./js/string 常用方法)
  • 83.预解析
  • 84.null与undefined的区别
  • 85.ES6新增的数组构造器
  • 86.深入理解动态作用域和词法作用域
  • 87.变量提升
  • 88.柯里化
  • 89.浅克隆
  • 90.深克隆
  • 91.js的运行机制
  • 92.工厂模式
  • 93.简述BOM对象
  • 94.ajax
  • 95.void(0)
  • 96.原生实现排序算法
  • 97.HTTP状态码
  • 98.抽象工厂模式
  • [99.Map、FlatMap 和 Reduce](./js/Map、FlatMap 和 Reduce)
  • [100.Generator 实现](./js/Generator 实现)
  • 101.0.30000000000000004
  • 102.模拟jq的链模式
  • 103.箭头函数的this
  • 104.类数组对象
  • 105.执行上下文
  • 106.cors
  • 107.如何遍历数组
  • 108.Promise实现
  • 109.Proxy实现
  • 110.GET与POST的区别
  • 111.ES6模块与CommonJS的差异
12
SampsonKY

SampsonKY

Dreams are destined to be lonely, and there is no doubt and ridicule on the road, but what about it, even if it is bruised and bruised, it must live beautifully.

18 日志
3 分类
15 标签
RSS
GitHub E-Mail
© 2020 SampsonKY
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.4