# 网站

Vue.js笔记

Webpack笔记

# 好的学习资源:

《重新介绍 JavaScript》 (opens new window)—— Mozilla 出品的JS 教程

微软面向初学者的网络开发课程 (opens new window)

TypeScript 入门教程 - xcatliu (opens new window)

# 好的工具及速查手册:

Web 技术参考 - Mozilla官网权威参考手册

caniuse.com (opens new window) - JS、CSS等API浏览器兼容性检查

冴羽的博客 (opens new window) - JavaScript深入系列、ES6系列、React系列 26.2Kstar

50多个使用HTML、CSS和JS的迷你web项目 (opens new window) - 11.7K

千古前端图文教程 (opens new window) - 18.7K star

被删的前端博客 (opens new window) - 1.7K star

# 博客

您可能希望使用的10个鲜为人知的 Web api (opens new window)

ESLint vs. Prettier 对于 JavaScript 来说,最好的代码格式化库是什么?https://betterprogramming.pub/eslint-vs-prettier-57882d0fec1d

重构之路:webpack打包体积优化(超详细) (juejin.cn) (opens new window)

ECMAScript 2016 到 2019 的所有新功能 (opens new window) www.v2ex.com/t/635647

# 基本数据类型

# Number

//1到6之间的随机数 https://stackoverflow.com/a/4960020
Math.floor(Math.random() * 6) + 1 

function randomIntFromInterval(min, max) { // min and max included 
  return Math.floor(Math.random() * (max - min + 1) + min);
}

# Map

Object.fromEntries(aMap))

# 字符串处理

# startsWith

//确定一个字符串是否以另一个字符串开头。这个方法区分大小写。
//语法:其中 position 可选,在 str 中搜索 searchString 的开始位置,默认值为 0。
//如果在字符串的开头找到了给定的字符则返回true;否则返回false。
str.startsWith(searchString[, position])


const str1 = 'Saturday night plans';

console.log(str1.startsWith('Sat'));
// expected output: true

console.log(str1.startsWith('Sat', 3));
// expected output: false

# 相等比较

相等比较最好用===

If you know they are strings, then there's no need to check for type.

如果您知道它们是字符串,那么就不需要检查类型。

"a" == "b"

However, note that string objects will not be equal.

但是,请注意字符串对象不会相等。

new String("a") == new String("a") //will return false.

Call the valueOf() method to convert it to a primitive for String objects,

调用 valueOf ()方法将其转换为 String 对象的原语,

new String("a").valueOf() == new String("a").valueOf()// will return true

//对象转字符串
var str = JSON.stringify(jsObj);
//字符串转对象
var obj = JSON.parse(str); 

//----------字符串替换----------
var str = "1\n2\n3\n";
//将字母\n替换成分号
str = str.replace("\n",";");
//结果:1;2\n3\n 只替换了第一个
str = str.replace(/\n/g, ";");
//结果:1;2;3; replace 的第一个参数可以是正则表达式,/g标识是全文匹配(全局替换)

//----------字符串包含----------
//字符串stringA 是否包含字符串 stringB
stringA.includes(stringB)


var testDivs = Array.prototype.filter.call(testElements,function(testElement){
	return testElement.nodeName === 'DIV';
});


//base64编码解码
aaa = window.btoa('12345678')
window.atob(aaa)

# 字符的 Unicode 表示法

"\u0061"
// "a"

//超出\u0000~\uFFFF之间的字符:
"\uD842\uDFB7"
// "𠮷"
"\u20BB7"
// " 7"
"\u{20BB7}"
// "𠮷"
"\u{41}\u{42}\u{43}"
// "ABC"
let hello = 123;
hell\u{6F} // 123
'\u{1F680}' === '\uD83D\uDE80'
// true

# 循环字符串里的每个字符(ES6)

for (let codePoint of 'foo') {
  console.log(codePoint)
}
// "f"
// "o"
// "o"

# 正则篇

//去掉开头结尾的某个同样字符
pathname = "/share/video/6736813535613013260/"
location.pathname.replace(/^\/|\/$/g, '')
//输出:"share/video/6736813535613013260"

const regex = /prefix[0-9a-zA-Z]{1,20}/g;
var currentURL = decodeURIComponent(window.location.href);
var result = currentURL.match(regex)

# 全部替换

我们知道 string.replace ()函数只替换第一个匹配项。 可以通过在正则表达式的结尾添加/g 来替换所有匹配项

var example = "potato potato";
console.log(example.replace(/pot/, "tom")); 
// "tomato potato"
console.log(example.replace(/pot/g, "tom")); 
// "tomato tomato"

# URL

How to get the value from the GET parameters? 如何从GET请求获取参数值? https://stackoverflow.com/a/979995/4493393

var url_string = "http://www.example.com/t.html?a=1&b=3&c=m2-m3-m4-m5"; //window.location.href
var url = new URL(url_string);
var c = url.searchParams.get("c");
console.log(c);

# 数组Array

let fruits = ['Apple', 'Banana']
console.log(fruits.length)
// 2
let first = fruits[0]
// Apple

//last object最后一个
let last = fruits[fruits.length - 1]
// Banana
fruits.forEach(function(item, index, array) {
  console.log(item, index)
})
// Apple 0
// Banana 1

let newLength = fruits.push('Orange')
// ["Apple", "Banana", "Orange"]

let last = fruits.pop() // remove Orange (from the end)
// ["Apple", "Banana"]


//最后一个对象
console.log('last', [1, 3, 4, 5].slice(-1));//[5]
//最后一个对象
[1, 3, 4, 5].pop()
//最后5个对象
yourArray.slice(Math.max(arr.length - 5, 1))
//删除第一个对象,返回一个新的数组对象(原数组不改变)
yourArray.shift()
//删除第一个的对象,原数组改变
yourArray.splice(0, 1)

console.log('second_to_last', [1, 3, 4, 5].slice(-2));


//concat() 合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组
const array1 = ['a', 'b', 'c'];
const array2 = ['d', 'e', 'f'];
const array3 = array1.concat(array2);
console.log(array3);
//输出: Array ["a", "b", "c", "d", "e", "f"]





# 遍历

//遍历怎么break
[1, 2, 3].some(function(el) {
  console.log(el);
  return el === 2;//break的情况(条件)
});

//ECMAScript2015 (aka ES6) 
let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (let el of arr) {
  console.log(el);
  if (el === 5) {
    break;
  }
}

[1,2,3].every(function(el) {
    return !(el === 1);
});
//ES6
[1,2,3].every( el => el !== 1 )

# 包含

const pets = ['cat', 'dog', 'bat'];
console.log(pets.includes('cat'));
// expected output: true

# 提取唯一的值(去重)

We can create a new array only with the unique values by using the Set object and the Spread operator.

var entries = [1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 8, 4, 2, 1]
var unique_entries = [...new Set(entries)];
console.log(unique_entries);
// [1, 2, 3, 4, 5, 6, 7, 8]

# 数组元素洗牌

Every day I'm shufflin'

var my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(my_list.sort(function() {
    return Math.random() - 0.5
})); 
// [4, 8, 2, 9, 1, 3, 6, 5, 7]

# 合并多维数组

Simply by using the Spread operator.

var entries = [1, [2, 5], [6, 7], 9];
var flat_entries = [].concat(...entries); 
// [1, 2, 5, 6, 7, 9]

# 使用长度调整数组的大小/清空数组

如果我们想调整数组的大小,只需重写数组的长度:

var entries = [1, 2, 3, 4, 5, 6, 7];  
console.log(entries.length); 
// 7  
entries.length = 4;  
console.log(entries.length); 
// 4  
console.log(entries); 
// [1, 2, 3, 4]

# 对象

obj.constructor获取类型

var myArray = [1,2,3];
(myArray.constructor == Array); // true

2

//对象有没有值
var hasData = !!aObject;

//https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
//hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。
const object1 = {};
object1.property1 = 42;

console.log(object1.hasOwnProperty('property1'));
// expected output: true

console.log(object1.hasOwnProperty('toString'));
// expected output: false

console.log(object1.hasOwnProperty('hasOwnProperty'));
// expected output: false

防止对象是undefined

//node_modules/@vuepress/theme-default/util/index.js
headers = headers.map(h => Object.assign({}, h))

# 动态属性名

I always thought that I first had to declare an object before being able to assign a dynamic property.

const dynamic = 'flavour';
var item = {
    name: 'Coke',
    [dynamic]: 'Cherry'
}
console.log(item); 
// { name: "Coke", flavour: "Cherry" }

# 类型判断

Array.isArray(obj)


obj instanceof Array


if(Object.prototype.toString.call(someVar) === '[object Array]') {
    alert('Array!');
}


if(typeof someVar === 'string') {
    someVar = [someVar];
}


if (somevar.constructor.name == "Array") {
    // do something
}

# 类型转换

# number to string

We just have to use the concatenation operator with an empty set of quotation marks.

var converted_number = 5 + "";
console.log(converted_number);
// 5
console.log(typeof converted_number); 
// string

# string to number

All we need is the + operator.

Be careful with this one since it only works with 'string numbers'.

the_string = "123";
console.log(+the_string);
// 123

the_string = "hello";
console.log(+the_string);
// NaN

# 时间

//时间戳(毫秒)
let timestamp = +new Date();
let timestamp2 = Date.now();

//Date类型获取time stamp
your_date.getTime()

定时刷新

<script type="text/javascript">
function myrefresh() {
  window.location.reload();
}
setTimeout('myrefresh()', 9000);
</script>
//根据id获取元素
document.getElementById("YOUR_ID").innerHTML = "YOUR_CONTENT";
var $markdownElem = document.querySelector('#markdown');
//对象转字符串 JS打印对象
var str = JSON.stringify(jsObj);
//修改a标签的href属性
document.getElementById("abc").href="baidu.com"; 

//---------------字符串---------------
//最后几个字符 last few char
var lastFiveChars = "abcdefg".substr(-5);
str.substring(str.length - 1);
var lastLetter = str.charAt(str.length - 1)
str.slice(-1);

//字符串转对象
var str1 = JSON.parse(str);  
//在JavaScript中创建多行字符串
var html = `
  <div>
    <span>Some HTML here</span>
  </div>
`;

var str = "1\n2\n3\n";
//将字母\n替换成分号
str = str.replace("\n",";");
//结果:1;2\n3\n 只替换了第一个

str = str.replace(/\n/g, ";");
//结果:1;2;3; replace 的第一个参数可以是正则表达式,/g标识全文匹配

//根据class获取元素
var testElements = document.getElementsByClassName("btn");
var testDivs = Array.prototype.filter.call(testElements,function(testElement){
	return testElement.nodeName === 'DIV';
});

//获取iframe 元素	
document.getElementById("hongbaoframe").contentWindow.document.getElementById("aaa")
	
base64编码解码
aaa = window.btoa('12345678')
window.atob(aaa)


chrome 日本制作的一支创意广告,用一次关闭 300 个窗口创作了一支暖心的别样定格动画。 
http://www.wandoujia.com/eyepetizer/detail.html?vid=3324
for(var i = 0; i < 337; i++){window.open('http://www.google.co.jp/landing/motto/tabplay/' + i + '.jpg');} 

document.getElementById('post-2199').style.background="#EEEEEE";


<div class="entry-content" style="background:#EEEEEE; color:#111111">


	//改变所有div的背景色
	var x=document.getElementsByTagName("div");
    for (var i = 0;i < x.length;i ++) {
        var a = x[i];
        a.style.background="#ddeedd";
    }
	//改变body背景色
    document.body.bgColor='#cccccc'
    		

# 语法

语句和声明

语句和声明 - JavaScript | MDN (mozilla.org) (opens new window)

# export

在创建JavaScript模块时,export 语句用于从模块(js文件)中导出实时绑定的函数、对象或原始值,以便其他程序可以通过 import 语句使用它们。

存在两种 exports 导出方式:

  1. 命名导出(每个模块包含任意数量)
  2. 默认导出(每个模块包含一个)
// 导出单个特性,let可以换成 var, const
export let name1, name2,, nameN; // also var, const
export let name1 =, name2 =,, nameN; // also var, const
export function FunctionName(){...}
export class ClassName {...}

// 导出列表(多个)
export { name1, name2,, nameN };

// 重命名导出
export { variable1 as name1, variable2 as name2,, nameN };

// 解构导出并重命名
export const { name1, name2: bar } = o;

// 默认导出
export default expression;
export default function () {} // also class, function*
export default function name1() {} // also class, function*
export { name1 as default,};


                               
// 导出模块合集
export * from …; // does not set the default export
export * as name1 from …; // Draft ECMAScript® 2O21
export { name1, name2,, nameN } from …;
export { import1 as name1, import2 as name2,, nameN } from …;
export { default } from …;

建议: 避免混合默认导出和命名导出

https://exploringjs.com/es6/ch_modules.html#sec_overview-modules

I generally recommend to keep the two kinds of exporting separate: per module, either only have a default export or only have named exports.

// Tips:默认导出实际上只是一个具有特殊名称 default 的命名导出。也就是说,以下两种说法是等价的:
import { default as foo } from 'lib';
import foo from 'lib';

//类似地,以下两个模块具有相同的默认导出:
//------ module1.js ------
export default function foo() {} // function declaration!
                               
//------ module2.js ------
function foo() {}
export { foo as default };

import 多次是否是同一个实例?

使用export let的时候是的

https://stackoverflow.com/a/57050195/4493393

同一文件的所有导入都将引用内存中的相同对象:https://stackoverflow.com/a/48763053/4493393

// File: yolo.js

class Yolo {}
export let yolo = new Yolo();

// File: laser.js

import { yolo } from "./yolo.js";
// yolo is a single instance of Yolo class


// File: cat.js

import { yolo } from "./yolo.js";
// same yolo as in laster.js

# function函数

# 箭头函数

// 成功的回调函数
function successCallback(result) {
  console.log("音频文件创建成功: " + result);
}

// 失败的回调函数
function failureCallback(error) {
  console.log("音频文件创建失败: " + error);
}

function createAudioFileAsync(yesyes, nono, cc) {
  console.log("异步创建音频文件")
  return { then: console.log }
}

function audioSettings() {
  console.log("音频设置")
}

function saySomething() {
  console.log("saySomething wakaka")
}
// createAudioFileAsync(audioSettings, successCallback, failureCallback)

// const promise = createAudioFileAsync(audioSettings);
// promise.then(successCallback, failureCallback);

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);

//箭头函数,https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions

// 用 Promise 来封装setTimeout方法
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

//使用
wait(2000).then(() => saySomething("到家了")).catch(failureCallback);

// 还原箭头函数
// 当箭头函数的函数体只有一个 `return` 语句时,可以省略 `return` 关键字和方法体的花括号,变成上面👆
const wait2 = ms => new Promise(function(resolve) {
  setTimeout(resolve, ms)
});

// 当箭头函数只有一个参数时,可以省略参数的圆括号,变成上面👆
const wait3 = ms => {
  return new Promise(function(resolve) {
    setTimeout(resolve, ms)
  })
};

// 下面的普通函数可以改写成如下的箭头函数
const wait4 = (ms) => {
  return new Promise(function(resolve) {
    setTimeout(resolve, ms)
  })
};

const wait5 = function(ms) {
  return new Promise(function(resolve) {
    setTimeout(resolve, ms)
  })
};


const wait22 = ms => new Promise(function(resolve, reject) {
  if (ms > 10000) {
    console.log("测试,时间太长了");
    reject("时间太长了")
  } else {
    setTimeout(resolve, ms)

  }
});

wait5(2000).then(() => saySomething("10 seconds")).catch(failureCallback);

# setTimeout

setTimeout(function () {
   //do something
 }, 800);


setTimeout(() => {
    //do something
}, 1000);

# 元素

获取iframe元素的元素

window.document.getElementById('subsite').contentWindow.document.getElementById('app').__vue__

# 异常处理

try {
  //你写的可能出现异常的代码
  parseSupported = parse("01") !== 1;
} catch (exception) {
  
}

# 良好习惯

# 美化代码

https://prettier.io/docs/en/cli.html

命令行美化语法:

prettier [options] [file/dir/glob ...]

例子

# 要运行本地安装的(即当前文件夹的)Prettier版本,请在命令前添加npx
npx prettier --write src/router/iframePage.vue

# git commit前自动格式化

https://prettier.io/docs/en/precommit.html

npx mrm lint-staged

# 缩短条件之少用if

Short Circuit Conditionals

Let's take this example:

if (available) {
    addToCart();
}

And shorten it by simply using the variable together with the function:

available && addToCart()

# 中高级

# 函数

# 默认参数值

function multiply(a, b = 1) {
  return a * b;
}

console.log(multiply(5, 2));
// expected output: 10

console.log(multiply(5));
// expected output: 5

# Promise

function buyTomatoes(sth) {
  console.log("买菜:",sth)
  const promise = new Promise(function(resolve, reject){
    if (sth === "tomato") {
      let obj = {msg:"success 买对菜了,可以进行下一步",code:200}
      resolve(obj);
    } else {
      reject(new Error("panda error 哎,买错了"));
    }
  });
  return promise;
}

function cooking(sth) {
  console.log("做饭:",sth)
}


//不需要buyTomatoes返回的结果
buyTomatoes("tomato").then(cooking("番茄炒蛋")).catch(function(pppres) {
  console.log("买错菜了",pppres)
})

//需要buyTomatoes返回的结果
buyTomatoes("tomato").then(ppres=> {
  console.log("买对菜了",ppres)
}).catch(function(pppres) {
  console.log("买错菜了",pppres)
})

buyTomatoes("potato").then(ppres=> {
  console.log("买对菜了",ppres)
}).catch(function(pppres) {
  console.log("买错菜了",pppres)
})

# Apply

使用率10% 难度40% 便利80%

// 用apply完成以避免循环,你可以
var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]

//而不必:
/* 
for (var i = 0; i < elements.length; i++) {
    array.push(elements[i]);
}
*/

修改Date new方法

//修复Safari new Date("2021-07-19 15:54:43") 返回Invalid Date的问题
Date = (function (Date) {
  MyDate.prototype = Date.prototype;
  // 将Date构造器的属性方法,复制到MyDate构造器上
  var propertys = Object.getOwnPropertyNames(Date.prototype.constructor);
  if (propertys && propertys.length > 0) {
    for (var i = 0; i < propertys.length; i++) {
      var name = propertys[i];
      MyDate[name] = Date.prototype.constructor[name];
    }
  }
  return MyDate;

  function MyDate() {
    // 当只有一个参数并且参数类型是字符串时,把字符串中的-替换为/
    if (arguments.length === 1) {
      let arg = arguments[0];
      if (
        Object.prototype.toString.call(arg) === "[object String]" &&
        arg.indexOf("T") === -1
      ) {
        arguments[0] = arg.replace(/-/g, "/");
      }
    }
    let bind = Function.bind;
    let unbind = bind.bind(bind);
    return new (unbind(Date, null).apply(null, arguments))();
  }
})(Date);

# import

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/import#%E5%8A%A8%E6%80%81import

import("../tool/pplog.js").then((module) => {
        // Do something with the module.
        console.log("modulemodulemodule", module.default.panda);
      });

# ESLint

./node_modules/eslint-loader/index.js error 'xxx' is defined but never used

Disabling a rule on a line or entirely on your project

https://stackoverflow.com/a/61875095

# JQuery

# event.stopPropagation()用法

<!DOCTYPE html>
<html>
<head lang="en">
   <meta charset="UTF-8">
   <script type="text/javascript" src="https://cdn.bootcss.com/jquery/1.5.1/jquery.min.js"></script>
</head>
<body onclick="MyBodyClick()">
 <div onclick="MyClickOut()">
  <div onclick="MyClickInner()">
    <span id="MySpan">
     I love JQuery!!
    </span>
  </div>
 </div>
</body>
<script type="text/javascript">
 function MyClickOut() {
  alert("outer Div");
 }
 function MyClickInner() {
  alert("Inner Div");
 }
 function MyBodyClick() {    
  alert("Body Click");
 }
 $(function () {
  $("#MySpan").bind("click", function (event) {
    alert("I'm span");
    //表面意思是停止传播,效果是点击最上层的元素,只有最上层的元素响应点击事件
    event.stopPropagation();
   
   
 })})
</script>
</html>

# 元素

//获取iframe 元素	
document.getElementById("xiaosongweb").contentWindow.document.getElementById("aaa")
//父获取子iframe
window.document.getElementById('subsite').contentWindow.document.getElementById('app').__vue__.globalVar.baseURL
//
document.getElementById("app").__vue__
//根据id获取元素
document.getElementById(id)
//根据class获取元素
document.getElementsByClassName("btn");
var list = document.getElementsByClassName("events");
for (let item of list) {
    console.log(item.id);
}

var list= document.getElementsByClassName("events");
[].forEach.call(list, function(el) {
    console.log(el.id);
});
chrome 日本制作的一支创意广告,用一次关闭 300 个窗口创作了一支暖心的别样定格动画。 
http://www.wandoujia.com/eyepetizer/detail.html?vid=3324
for(var i = 0; i < 337; i++){window.open('http://www.google.co.jp/landing/motto/tabplay/' + i + '.jpg');} 

document.getElementById('post-2199').style.background="#EEEEEE";


<div class="entry-content" style="background:#EEEEEE; color:#111111">


	//改变所有div的背景色
	var x=document.getElementsByTagName("div");
    for (var i = 0;i < x.length;i ++) {
        var a = x[i];
        a.style.background="#ddeedd";
    }
	//改变body背景色
    document.body.bgColor='#cccccc'
    		

###event.stopPropagation();用法

<!DOCTYPE html>
<html>
<head lang="en">
   <meta charset="UTF-8">
   <script type="text/javascript" src="https://cdn.bootcss.com/jquery/1.5.1/jquery.min.js"></script>
</head>
<body onclick="MyBodyClick()">
 <div onclick="MyClickOut()">
  <div onclick="MyClickInner()">
    <span id="MySpan">
     I love JQuery!!
    </span>
  </div>
 </div>
</body>
<script type="text/javascript">
 function MyClickOut() {
  alert("outer Div");
 }
 function MyClickInner() {
  alert("Inner Div");
 }
 function MyBodyClick() {    
  alert("Body Click");
 }
 $(function () {
  $("#MySpan").bind("click", function (event) {
    alert("I'm span");
    event.stopPropagation();
   
   
 })})
</script>
</html>

Undefined 测试

var aaa = undefined
console.log('----'+aaa+'----'+typeof(aaa)); 
var bbb = 'undefined'
console.log('----'+bbb+'----'+typeof(bbb)); 
var ccc ;
console.log('----'+ccc+'----'+typeof(ccc)); 
if(aaa == 'undefined') {
	console.log('666666'); 
}
if(aaa == undefined) {
	console.log('777777'); 
}

# npm及JS库

https://bennettfeely.com/ztext/ 这个 JS 库可以将任何字体变成 3D 效果,支持中文。

HTML+CSS+JS在同一个窗口 https://tryenlight.github.io/demo/code-editor-project/index.html https://flems.io/

Code Playgrounds

https://jsfiddle.net/ http://codepen.io/ http://jsbin.com/

UI https://chakra-ui.com/docs/form/button

https://github.com/cowboy/javascript-hooker

# npm

#查看是谁依赖了browserify-sign
npm ls browserify-sign

npm-check (opens new window)是用来检查npm依赖包是否有更新,错误以及不在使用的,我们也可以使用npm-check进行包的更新。

全局安装npm-check:

$ npm install -g npm-check
/usr/local/bin/npm-check -> /usr/local/lib/node_modules/npm-check/bin/cli.js
  • 检查npm包的状态:
npm-check -u -g

# 小技巧

# Chrome调试技巧

查看某元素所有CSS样式:右键审查元素然后选择Computed选项卡

# 显示所有元素边界

来源 (opens new window)

var style = document.querySelector('#_outline_');
 if (style) { 
  style.parentNode.removeChild(style); 
 } else { 
  style = document.createElement('style');
  style.id = '_outline_';
  style.innerHTML = "*{outline: 1px solid red}";
  document.body.appendChild(style); 
 }
上次更新: 3/16/2022, 2:29:37 PM