javascript

Axios 的基本使用

fetch 虽然在现代浏览器中已经支持很好了,但是 API 还是没有那么好用。比如说增加 GET 参数必须使用 URLSearchParm 这个类。相比之下,Axios 的 API 还是更接近直觉一些。

import axios from 'axios'

axios(url, [config]);
axios(config);
axios.get(url, [config])
axios.delete(url, [config])
axios.put(url, data, [config])
axios.post(url, data, [config])

// 请求中 config 的属性
const config = {
    headers: {}, // Headers
    params: {},  // GET 参数
    data: {},  // 默认情况下 {} 会按照 JSON 发送
    timeout: 0, // 默认是没有 timeout 的
}

// 如果要发送传统的 POST 表单
const config = {
    data: new FormData()
}

// headers 会根据 data 是 json 还是表单自动设置,非常贴心。

// 响应的属性
let res = await axios.get("api")
res = {
    data: {},  // axios 会自动 JSON.parse
    status: 200,
    statusText: "OK",
    headers: {},
    config: {},
    request: {}
}
// 和 fetch 不同的是,res.data 可以直接使用,而 fetch 还需要 await res.json()

// 如果要添加一些默认的设置,使用
axios.defaults.headers.common["X-HEADER"] = "value"
axios.defaults.timeout = 3000
// 具体参见这里: https://github.com/axios/axios/blob/master/lib/defaults.js#L28

重定向与其他错误状态码

对于 3XX 重定向代码,axios 只能跟中,这是浏览器决定的,不是 axios 可以改变的。
对于 4XX 和 5XX 状态码,axios 会抛出异常,可以 catch 住。

上传文件

如果一个表单中包含的文件字段,那么传统的方法是把这个字段做为表单的一部分上传。然而现代的 API 大多是 json 接口,并没有 POST 表单这种格式。
这时候可以单独把上传作为一个接口,通过 POST 表单的方式上传,然后返回上传后的路径。在对应的 API 的接口中附件的字段填上这个路径就好了。

参考

  1. https://stackoverflow.com/questions/4083702/posting-a-file-and-associated-data-to-a-restful-webservice-preferably-as-json

Python 和 JavaScript 语法对比

命名

  1. 注意使用驼峰变量名,不要使用下划线变量名

字符串

格式化

JavaScript:

`hello ${name}`

Python:

f"hello {name}"

文件

打开文件:

JavaScript:

const fs = require(fs).promises;  // 使用 async/await 版本的 fs 模块

await fs.writeFile(filename, data);  // 写入文件

// 文件是否存在
try {
  await fs.stat(filename)
  exitst = true
} catch (e) {
  exists = false
}

Python:

with open(filename, w) as f:
    f.write(data)

os.path.exists(filename)  # 文件是否存在

数组

切片:

JavaScript:

const arr1 = arr2.slice(3, 5);

Python:

arr1 = arr2[3:5]

html Node vs Element

  • Node vs Element

HTML Document consists of different node, element is one type of node.

  • NodeList vs HTMLCollection

NodeList is a collection of node, HTMLCollection is a collection of element.

  • HTMLCollection vs NodeList vs Array

HTMLCollection 和 NodeList 都是动态的,会随着 DOM 的变化而变化

Array 是静态的数据结构

浏览器用于替换 ajax/xhr 的 fetch api

fetch 是近年来浏览器实现的一个用于取代 xhr 的 API,相比于 xhr 来说更加简单易用安全且强大。主要区别有:

  • fetch 基于 promise,可以使用 await 直接调用;
  • fetch 对于 400 和 500 错误依然会正常返回而不会报错。只有在网络错误的时候才会抛出异常;
  • fetch 默认只会携带同一个域名下的 cookies,也就是 same-origin,默认更安全;
  • fetch 不接受跨域的 Set-Cookie。

基本用法

如果要在 node 中使用的话,需要安装 isomophic-unfetch:

yarn add isomorphic-unfetch
import fetch from 'isomorphic-unfetch'

const response = await fetch("http://example.com/movies.json");
const myJson = await response.json(); // text() 返回纯文本
console.log(JSON.stringify(myJson));
  • response.ok 是否请求返回了 2XX 代码
  • response.status 返回的状态码,比如 200, 404 等
  • await response.blob() 返回二进制文件
  • await response.text() 返回文本文件
  • await response.json() 返回解析的 json

增加选项

特别注意的是,在 Flask 等后端框架中,如果不添加 application/json 的 header, 默认不会解析 json, 太坑了。默认情况下 fetch 是会携带同一个域名下的 Cookie 的

try {
  // Default options are marked with *
  const response = await fetch(url, {
    method: "POST", // *GET, POST, PUT, DELETE, etc.
    mode: "cors", // no-cors, *cors, same-origin
    cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
    credentials: "same-origin", // include, *same-origin, omit
    headers: {
      "Content-Type": "application/json"
      // "Content-Type": "application/x-www-form-urlencoded",
    },
    redirect: "follow", // manual, *follow, error
    referrer: "no-referrer", // no-referrer, *client
    body: JSON.stringify(data) // body data type must match "Content-Type" header
  });
  console.log(await response.json());
} catch (error) {
  console.error(error);
}

添加 URL 参数

var url = new URL('https://sl.se')

var params = {lat:35.696233, long:139.570431} // or:
var params = [['lat', '35.696233'], ['long', '139.570431']]

url.search = new URLSearchParams(params).toString();

fetch(url)

在 Node 中可能需要:import {URL, URLSearchParams} from 'url'

携带 cookies

fetch 的 credentials 有三个选项:

  • omit 不携带任何 cookies
  • include 携带所有 cookies
  • same-origin 只有向当前网站的同源域名发送请求时才携带 cookies

其中 same-origin 是默认选项。

使用自定义 headers 和 request

const headers = new Headers();
headers.append("Content-Type", "text/plain");
headers.append("Content-Length", content.length.toString());
headers.append("X-Custom-Header", "ProcessThisImmediately");

// 另一种方法是直接使用字典
const headers = new Headers({
  "Content-Type": "text/plain",
})

const init = {
  method: "POST",
  headers: headers,
  mode: "cors",
  cache: "default",
}

const request = new Request("flowers.jpg", init);
const rsp = await fetch(request);

参考

  1. https://developer.mozilla.org/en-US/docs/Web/API/FetchAPI/UsingFetch
  2. https://stackoverflow.com/questions/34558264/fetch-api-with-cookie
  3. https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials

JavaScript snippets

get parameter from url

function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}

JavaScript 网页选择 API

basics

window.getSelection and document.getSelection all returns the Selection object, the selection object is almost useless.

window.getSelection.getRangeAt(0) returns a Range object. for history reasons, there is only one range in each selection.

rangeAncestor = range.commonAncestorContainer; commonAncestorContainer is the common ancestor of the range elements.

jQuery and un-jQuery

jQuery

$el.append(htmlString)
$el.prepend(htmlString)

$newEl.insertBefore(queryString)
$newEl.insertAfter(queryString)

un-jQuery

DOM 操作

选择器可以使用 querySelector 和 querySelectorAll, 但是这两个的性能太差了,最好使用 getElementById, getElementsByTagName, getElementsByClassName

$el.val() 对应 el.value

获取 attr

$el.attr('id');
el.getAttribute('id);
el.setAttribute(attr, value)

parent and children

$el.children
$el.parent()
el.children
el.parentNode

设置 css

$el. css({color: '#000'});
el.style.color = '#000';
$el.css('color');
window.getComputedStyle(el)['color'];

特别地
$(el).hide(); // jQuery
el.style.display = ‘none’; // native
$(el).show(); // jQuery
el.style.dispaly = ”

设置 class

$el.addClass(className) // remove, has, toggle
el.classList.add(className) // remove, contains, toggle

设置 text
Get text
// jQuery
$el.text();
// Native
el.textContent;

Set text
// jQuery
$el.text(string);

// Native
el.textContent = string;

设置 html

Get HTML
// jQuery
$el.html();

// Native
el.innerHTML;
Set HTML
// jQuery
$el.html(htmlString);

// Native
el.innerHTML = htmlString;

inserting html fragment to document

Have a look at insertAdjacentHTML

var element = document.getElementById("one");
var newElement = '<div id="two">two</div>'
element.insertAdjacentHTML( 'afterend', newElement )
// new DOM structure: <div id="one">one</div><div id="two">two</div>
position is the position relative to the element you are inserting adjacent to:

beforebegin Before the element itself

afterbegin Just inside the element, before its first child

beforeend Just inside the element, after its last child

afterend After the element itself

事件

绑定事件
$el.on(eventName, eventHandler); // jQuery
el.addEventListener(eventName, eventHandler); // Native

解绑事件
$el.off(eventName, eventHandler); // jQuery
el.removeEventListener(eventName, eventHandler); // Native

触发事件
// 用户事件
$(el).trigger(‘custom-event’, {key1: ‘data’}); // jQuery
// Native, note that
const event = new CustomEvent(‘custom-event’, {detail: {key1: ‘data’}});
el.dispatchEvent(event);

// 原生事件
$(el).trigger(‘change’);
var ev = new Event(“look”, {“bubbles”:true, “cancelable”:false});
document.dispatchEvent(ev);

ajax

getJSON
jQuery
$.getJSON(‘/my/url’, function(data) {
});
IE9+
var request = new XMLHttpRequest();
request.open(‘GET’, ‘/my/url’, true);
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// Success!
var data = JSON.parse(request.responseText);
} else {
// We reached our target server, but it returned an error
}
};
request.onerror = function() {
// There was a connection error of some sort
};
request.send();
Post
jQuery
$.ajax({
type: ‘POST’,
url: ‘/my/url’,
data: data
});
IE8+
var request = new XMLHttpRequest();
request.open(‘POST’, ‘/my/url’, true);
request.setRequestHeader(‘Content-Type’, ‘application/x-www-form-urlencoded; charset=UTF-8’);
request.send(data);
Request
jQuery
$.ajax({
type: ‘GET’,
url: ‘/my/url’,
success: function(resp) {
},
error: function() {
}
});
IE9+
var request = new XMLHttpRequest();
request.open(‘GET’, ‘/my/url’, true);
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// Success!
var resp = request.responseText;
} else {
// We reached our target server, but it returned an error
}
};
request.onerror = function() {
// There was a connection error of some sort
};
request.send();

DOM Ready

https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md
http://youmightnotneedjquery.com/

JavaScript DOM API

document object

attributes of document object

document.title               // 设置文档标题等价于 HTML 的<title>标签
document.URL                 // 设置 URL 属性从而在同一窗口打开另一网页
document.fileCreatedDate     // 文件建立日期,只读属性
document.fileModifiedDate    // 文件修改日期,只读属性
document.fileSize            // 文件大小,只读属性
document.cookie              // 设置和读出 cookie
document.charset             // 设置字符集 简体中文:gb2312
document.body         // body 元素
document.location.hash/host/href/port          // location

methods of document object

getElementById() // 返回一个 Element
getElementsByName() // 根据 name 属性获得元素,返回一个 NodeList
getElementsByTagName() // 返回一个 HTMLCollection/NodeList(Webkit)
getElementsByClassName() // 返回一个 HTMLCollection
querySelector() // 返回一个符合的元素,性能很差
querySelectorAll() // 返回所有符合的元素组成的 NodeList, 性能很差
document.write()
document.createElement()

window object

functions in window object

setTimeout(func, milliseconds, parameters...)
setInterval(func, milliseconds, parameters...)

NOTE: javascript is asynchonous, even if you set 0 timeout, the function is just put into the execute queue, not invoked immediately.

window.location

location    setting location will cause the page to redirect to new page
location.href
location.protocol
location.host
location.hostname
location.port
location.pathname
location.search
location.hash
location.assign()    go to a new address
location.replace()   go to a new address and do not disturb the history
location.reload()   reload the page

window.history

history.back()
history.forward()
history.go(number)

window.screen

window.screen.width screen width, not the viewport width
window.screen.height screen height

alert, confirm and prompt

alert show a message
confirm return a bool by user action
prompt

Same Origin Policy

document.domain is the key to decide the origin of a script.

scripts under different subdomain can set the their document.domain to a same domain, and then then can share the same cookie or communicate

Cross-Origin Resource Sharing