var utils = {};
utils.dynamicLoad = {
css: (href, onloadCallbackStr) => {
let loadStr = `
(function () {
var hm = document.createElement("link");
hm.href = "${href}";
// 注意: 需要设置以下两项, 浏览器才会加载
hm.setAttribute("rel", "stylesheet");
hm.setAttribute("type", "text/css");
hm.onload = () => {
${onloadCallbackStr};
// 加载完就删除
// hm.remove();
};
var heads = document.getElementsByTagName("head");
if(heads.length)
heads[0].appendChild(hm);
else
document.documentElement.appendChild(hm);
})();`;
return loadStr;
},
js: (src, onloadCallbackStr) => {
let loadStr = `
(function () {
var hm = document.createElement("script");
hm.src = "${src}";
hm.onload = () => {
${onloadCallbackStr};
// 加载完就删除
// hm.remove();
};
var heads = document.getElementsByTagName("head");
if(heads.length)
heads[0].appendChild(hm);
else
document.documentElement.appendChild(hm);
})();`;
return loadStr;
}
};
export default utils;
<!-- 注释节点值 -->
参考:
// 从 body 开始向内查找
var bodyElement = document.getElementsByTagName("body")[0];
for (var i=0; i<bodyElement.childNodes.length; i++) {
// 注释节点 类型 为 8
if (bodyElement.childNodes[i].nodeType == 8) {
console.log(bodyElement.childNodes[i].nodeValue);
}
}
但是这个只能找到body的子节点是注释的情况, 当然,就这样一直循环下去也可以找到body子节点的子节点是注释的情况,但是如果在很深的DOM节点里,用这种循环的方式就很不好书写。 所以我想到用递归来写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div>
<div>
<div>
<!-- note1 -->
</div>
</div>
<div>
<div></div>
</div>
</div>
<div>
<div>
<p>
<!-- note2 -->
<p>
</div>
<div>
<div></div>
</div>
</div>
<!-- note3 -->
<div>
<div>
<div></div>
</div>
<!-- note4 -->
<div>
<div></div>
</div>
</div>
<script type="text/javascript">
function eachComment(ele) {
for (var i=0; i<ele.childNodes.length; i++) {
var child = ele.childNodes[i];
if (child.nodeType == 8) {
console.log(child.nodeValue);
} else if (child.childNodes) {
eachComment(child);
}
}
}
var bodyElement = document.getElementsByTagName("body")[0];
eachComment(bodyElement);
</script>
</body>
</html>
注意:
<!-- PluginCore.IPlugins.IPluginWidget -->
用console.log(child.nodeValue);
得到的值 是PluginCore.IPlugins.IPluginWidget
两边有空格, 也nodeValue
就是内部内容, 不会去除两边空格的
参考:
经过测试, 注释节点也可以用
const span = document.createElement("span");
注释节点.replaceWith(span)
// 注意: 注释节点不变, 注释节点 依然指向原来的 , 而不是 replaceWith 后的
// 注意: 经测试: 不同节点.replaceWith(node1) 时, node1 对象不要重复使用, 否则可能导致想象外效果
temp1.replaceWith("<h1>aaa</h1>")
// 这样会替换为 nodeValue: '<h1>aaa</h1>' 的文本节点
正确做法
c = parseDom("<h1>ccc</h1>")
// 注意: 不要省略 "..."
temp4.replaceWith(...c)
我可以使用
replaceWith
将任意一个子跨度与多个元素和文本节点交换吗
Element.replaceWith()的签名接受数量可变的Node
或DOMString
参数。。。
replaceWith(...nodes)
replaceWith()
var parent = document.createElement("div");
var child = document.createElement("p");
parent.appendChild(child);
var span = document.createElement("span");
child.replaceWith(span);
console.log(parent.outerHTML);
// "<div><span></span></div>"
参考:
只读属性
Node.nodeType
表示的是该节点的类型。
var type = node.nodeType;
返回一个整数,其代表的是节点类型。其所有可能的值请参考 节点类型常量.
常量 | 值 | 描述 |
---|---|---|
Node.ELEMENT_NODE | 1 | 一个 元素 节点,例如 ](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/p) 和 [。 |
Node.TEXT_NODE | 3 | Element 或者 Attr 中实际的 文字 |
Node.CDATA_SECTION_NODE | 4 | 一个 CDATASection,例如 <!CDATA[[ … ]]>。 |
Node.PROCESSING_INSTRUCTION_NODE | 7 | 一个用于XML文档的 ProcessingInstruction (en-US) ,例如 <?xml-stylesheet ... ?> 声明。 |
Node.COMMENT_NODE | 8 | 一个 Comment 节点。 |
Node.DOCUMENT_NODE | 9 | 一个 Document 节点。 |
Node.DOCUMENT_TYPE_NODE | 10 | 描述文档类型的 DocumentType 节点。例如 <!DOCTYPE html> 就是用于 HTML5 的。 |
Node.DOCUMENT_FRAGMENT_NODE | 11 | 一个 DocumentFragment 节点 |
不同的节点类型
document.nodeType === Node.DOCUMENT_NODE; // true
document.doctype.nodeType === Node.DOCUMENT_TYPE_NODE; // true
var fragment = document.createDocumentFragment();
fragment.nodeType === Node.DOCUMENT_FRAGMENT_NODE; // true
var p = document.createElement("p");
p.textContent = "很久很久以前...";
p.nodeType === Node.ELEMENT_NODE; // true
p.firstChild.nodeType === Node.TEXT_NODE; // true
注释
// 该示例会检查 document 下第一个节点是不是注释,如果不是,则会提醒。
var node = document.documentElement.firstChild;
if (node.nodeType != Node.COMMENT_NODE)
console.log("你应该认真编写代码注释!");
删除 Element 节点
参考:
function parseDom(arg) {
var objE = document.createElement("div");
objE.innerHTML = arg;
return objE.childNodes;
};
参考:
Promise based HTTP client for the browser and node.js
Using npm:
npm install axios
Using unpkg CDN:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
const axios = require('axios');
// Send a POST request
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
// GET request for remote image in node.js
axios({
method: 'get',
url: 'http://bit.ly/2mTM3nY',
responseType: 'stream'
})
.then(function (response) {
response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
});
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
// `responseType` indicates the type of data that the server will respond with
// options are: 'arraybuffer', 'document', 'json', 'text', 'stream'
// browser only: 'blob'
responseType: 'json', // default
Global axios defaults
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
Custom instance defaults
// Set config defaults when creating the instance
const instance = axios.create({
baseURL: 'https://api.example.com'
});
// Alter defaults after instance has been created
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
// 注意: timeout 的单位 是 ms, 因此这里是 2.5 seconds
instance.defaults.timeout = 2500;
utils/request.js
import axios from "axios";
import qs from "qs";
// build 环境
// axios.defaults.baseURL = 'http://api.tikotiko.fun';
// axios.defaults.baseURL = 'http://localhost:4530/';
axios.defaults.baseURL = process.env.VUE_APP_API;
// axios 请求拦截 - 在发送请求之前做某件事
axios.interceptors.request.use(
function(request) {
// 解决跨域 post 变 OPTIONS,导致 404
if (request.method === "post") {
request.headers["Content-Type"] =
"application/x-www-form-urlencoded;charset=UTF-8";
request.data = qs.stringify({
...request.data
});
}
// 如果有登录状态token的话,则添加到请求头
if (localStorage.token) {
// 在 headers 中设置 Authorization 属性放token,token是存在缓存中的
request.headers.Authorization = `Bearer ${localStorage.token}`;
}
return request;
},
function(error) {
return Promise.reject(error);
}
);
/**
* 发送http请求
* @param {String} url 目标rl
* @param {String} method 方法get,post,put etc.
* @param {Object} params 对象参数
* @returns {Promise<unknown>}
*/
const request = function(url, method, params) {
return new Promise((resolve, reject) => {
if (method == "get") {
axios({
url: url,
method: "get",
params: params
})
.then(res => {
res.data.status = res.status;
resolve(res.data);
})
.catch(err => {
err.data.status = err.status;
reject(err.data);
});
} else {
axios({
url: url,
method: method,
data: params
})
.then(res => {
res.data.status = res.status;
resolve(res.data);
})
.catch(err => {
err.data.status = err.status;
reject(err.data);
});
}
});
};
export default request;
使用 request.js api/plugins.js
import request from "@/utils/request.js";
export page => request("/article/last", "get", { page: page });
export pluginId => request("/plugincore/admin/plugins/install", "post", { pluginId: pluginId });
参考:
XMLHttpRequest
本身就是支持responseType
补充: 默认
xhr 请求
会 自动 带上Cookie
补充: 动态插入JS可以不阻碍 DOMContentLoad
参考:
Cookie是不可以跨域名的,隐私安全机制禁止网站非法获取其他网站的Cookie。
正常情况下,同一个一级域名下的两个二级域名也不能交互使用Cookie,比如test1.mcrwayfun.com和test2.mcrwayfun.com,因为二者的域名不完全相同。如果想要mcrwayfun.com名下的二级域名都可以使用该Cookie,需要设置Cookie的domain参数为.mcrwayfun.com,这样使用test1.mcrwayfun.com和test2.mcrwayfun.com就能访问同一个cookie。
一级域名又称为顶级域名,一般由字符串+后缀组成。熟悉的一级域名有baidu.com,qq.com。com,cn,net等均是常见的后缀。 二级域名是在一级域名下衍生的,比如有个一级域名为mcrfun.com,则blog.mcrfun.com和www.mcrfun.com均是其衍生出来的二级域名。
path属性决定允许访问Cookie的路径。比如,设置为"/"表示允许所有路径都可以使用Cookie。
以上种种,证明sessionStorage里面的session,并不同于cookie,是以tab为级别的session。
localStorage与sessionStorage虽然相似,但是访问限制却不尽相同,localStorage的访问域默认设定为设置localStorage的当前域,其他域名不可以取。 这点与sessionStorage相同,但是与sessionStorage不同的是,localStorage设定后,新开tab是可以访问到的。
localStorage理论上讲是 永久性质的存储。但是,免不了用户会使用浏览器清除数据,或者浏览器有时候为了节省,去清除数据。
感谢帮助!