目录

概括

技术积累

node-sass

cnpm i
1

不然会报错

vue 过滤器

查看代码
  filters: {
    ellipsis(value) {
      if (!value) return ''
      if (value.length > 8) {
        return value.slice(0, 8) + '...'
      }
      return value
    }
  }
1
2
3
4
5
6
7
8
9

在 3.x 中,过滤器已移除,且不再支持。取而代之的是,我们建议用方法调用或计算属性来替换它们。

主动触发 element 表单的检查

查看代码
this.$refs.ruleForm.validateField("content");
1

使用 vuepress 内置组件 codegroup

yarn
npm install

在 vue 中实现 p5 有点恶心心 1.使用 toDataURL 把 canvas 转换成 base64 图片地址 2.或者用 refs 把 canvas "appendChild"到 vue 组件中 3.组件中导入 p5,其中 p5 的方法都要加'p5.',否则会报错

vue的组件代码如下
查看代码
mounted() { this.$nextTick(()=>{ let judgeCanvasExist =
document.getElementById("defaultCanvas0") if(judgeCanvasExist===null) { new
P5(this.main); } }) }, methods: { main(_p5) { let p5 = _p5; let bubbles = [];
const window_width = window.innerWidth; const window_height =
window.innerHeight; p5.setup = () => { p5.createCanvas(window_width / 4,
window_height / 4); for (let i = 0; i < 100; i++) { let x = p5.random(p5.width);
let y = p5.random(p5.height); let r = p5.random(20, 60); let b = new Bubble(x,
y, r); bubbles.push(b); }; let
myCanvas=document.getElementById("defaultCanvas0"); let container =
this.$refs.box; container.appendChild(myCanvas) // let dataUrl =
myCanvas.toDataURL(); //base64 // this.canvasUrl = dataUrl; //
console.log(typeof myCanvas) // console.log(myCanvas.parentNode) // debugger //
myCanvas.parentNode.removeNode(myCanvas) } p5.mouseMoved = () => { for (let i =
bubbles.length - 1; i >= 0; i--) { if (bubbles[i].contains(p5.mouseX,
p5.mouseY)) { bubbles.splice(i, 1); } } } p5.draw = () => { p5.background(0);
for (let i = 0; i < bubbles.length; i++) { if (bubbles[i].contains(p5.mouseX,
p5.mouseY)) { bubbles[i].changeColor(255); } else { bubbles[i].changeColor(0); }
bubbles[i].move(); bubbles[i].show(); } } class Bubble { constructor(x, y, r) {
this.x = x; this.y = y; this.r = r; this.brightness = 0; } changeColor(bright) {
this.brightness = bright; } contains(px, py) { let d = p5.dist(px, py, this.x,
this.y); if (d < this.r) { return true; } else { return false; } } move() {
this.x = this.x + p5.random(-2, 2); this.y = this.y + p5.random(-2, 2); } show()
{ p5.stroke(255); p5.strokeWeight(4); p5.fill(this.brightness, 125);
p5.ellipse(this.x, this.y, this.r * 2); } } } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
查看代码
copy(document.cookie);
//粘贴并应用
"复制的内容".split(";").map((c) => (document.cookie = c));
1
2
3

echarts 的图标监听 window 的大小重绘

查看代码
window.addEventListener("resize", () => {
  this.chartLine.resize();
});
1
2
3
在博客这里使用的 Echart5 和 vue3,在 mounted 阶段加入上述这行代码,报错了
Uncaught Error: `resize` should not be called during main process.
1
查看代码
const cookie = (name) =>
  `;${document.cookie}`.split(`${name}=`).pop().split(";").shift();
//使用
//cookie('pgv_pvid');
1
2
3
4

将 rgb 转换成十六进制

查看代码
const rgbToHex = (r, g, b) =>
  "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
//1<<24===1*Math.pow(2,24)
//使用
//rgbToHex(0,51,255)
//toString(16)表示转换成16进制后再转换成字符串
1
2
3
4
5
6

复制到剪贴板

查看代码
const copyToClipboard = async (text) => navigator.clipboard.writeText(text);
//使用
//copyToClipboard('hello world')
//Clipboard API是下一代的剪贴板操作方法,比传统的document.exeCommand()方法更强大、更合理
//如果你把上面的代码,粘贴到开发者工具里面运行,就会报错。因为代码运行的时候,开发者工具窗口是当前页,这个页面不存在 Clipboard API 依赖的 DOM 接口。一个解决方法就是,相关代码放到setTimeout()里面延迟运行,在调用函数之前快速点击浏览器的页面窗口,将其变成当前页。
//参照https://www.ruanyifeng.com/blog/2021/01/clipboard-api.html
/*
setTimeout(async () => {
  copyToClipboard('hello world')
}, 2000);
*/
1
2
3
4
5
6
7
8
9
10
11

数组去重

查看代码
(target) => {
  let arr = target;
  let res = [new Set(arr)];
  return res;
};
1
2
3
4
5

深拷贝

查看代码
function deepClone(target) {
  debugger;
  let result;
  if (typeof target === "object") {
    if (Array.isArray(target)) {
      result = [];
      for (let i in target) {
        result.push(deepClone(target[i]));
      }
    } else if (target === null) {
      result = null;
    } else if (target.constructor === RegExp) {
      result = target;
    } else {
      result = {};
      for (let i in target) {
        result[i] = deepClone(target[i]);
      }
    }
  } else {
    result = target;
  }
  return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

使用 Map 深拷贝

查看代码
function deepCloneMethod(target) {
  const map = new Map();
  function isObject(val) {
    return val != null && typeof val === "object";
  }
  function clone(target) {
    if (isObject(target)) {
      let cloneTarget = Array.isArray(target) ? [] : {};
      if (map.get(target)) {
        return map.get(target);
      }
      map.set(target, cloneTarget);
      for (const key in target) {
        cloneTarget[key] = clone(target[key]);
      }
      return cloneTarget;
    } else {
      return target;
    }
  }
  return clone(target);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

判断字符串是否全为空

str.match(/^[ ]*$/);
1

判断对象是否为空

查看代码
//使用Object.keys()或者Object.getOwnPropertyNames()
const obj = {};
const arr = Object.keys(obj);
console.log(arr.length > 0);
//使用JSON.stringfy()
console.log(JSON.stringify(obj) !== "{}");
1
2
3
4
5
6

注意

Object.keys(), 它返回一个数组,这个数组由对象中可枚举的自有属性的名称组成。 Object.getOwnPropertyNames() 返回一个数组,该数组对元素是 obj 自身拥有的枚举或不可枚举属性名称字符串。

检查日期是否有效

查看代码
const isDateValid = (...val) => !Number.isNaN(new Date(...val).valueOf());
//使用
//isDateValid(new Date())
//true
//new Date()
//Thu Nov 18 2021 21:11:16 GMT+0800 (中国标准时间)
//格林威治的子午线向东偏移8小时
1
2
3
4
5
6
7

查找一年中的某一天

查看代码
const dayOfYear = (date) =>
  Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24);
//dayOfYear(new Date())
//322
1
2
3
4

大写字符串

查看代码
const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
//使用
//capitalize('heiheiheiyohei')
1
2
3

create-vueopen in new window

npm init vue@next
1

给所有的 div 一个 outline 样式

查看代码
[].forEach.call($("div"), (a) => {
  a.style.outline =
    "5px solid #" + (~~(Math.random() * (1 << 24))).toString(16);
});
1
2
3
4

屏幕录制

查看代码
  • index.js
let btn = document.querySelector(".record-btn");
btn.addEventListener("click", async function () {
  let stream = await navigator.mediaDevices.getDisplayMedia({
    video: true,
  });
  const mine = MediaRecorder.isTypeSupported("video/webm;codecs=vp9")
    ? "video/webm;codecs=vp9"
    : "video/webm";
  let mediaRecoder = new MediaRecorder(stream, {
    mimeType: mine,
  });
  let chunks = [];
  mediaRecoder.addEventListener("dataavailable", function (e) {
    chunks.push(e.data);
  });
  mediaRecoder.addEventListener("stop", function () {
    let blob = new Blob(chunks, {
      type: chunks[0].type,
    });
    let url = URL.createObjectURL(blob);
    let video = document.querySelector(".video");
    video.src = url;
    let a = document.createElement("a");
    a.href = url;
    a.download = "video.webm";
    a.click();
  });
  mediaRecoder.start();
});
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

html

<video width="600px" class="video" controls="controls"></video>
<button class="record-btn">开始录制</button>
1
2

代理页面解决跨域(子页面 iframe 访问父页面)

查看详情
父页面 server1/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    server1
    <iframe src="http://127.0.0.1:5500/index.html"></iframe>

    <script>
        window.sessionStorage.setItem('item',1);
        function doSomethin (){
            console.log('server1');
            console.log(window.sessionStorage.getItem('item'))
        }

    </script>
    
</body>
</html>
子页面 server2/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

</head>
<body>
    serer2
    <button onclick="doSome()">
        跨域
    </button>
    <script>
        function doSome(){
            console.log(this)
            if(!document.getElementById('crossFrmane')){
                var iframe = document.createElement('iframe');
                iframe.setAttribute('style','position:absolute;left:-199999px;top=-1929999px');
                iframe.setAttribute('src','http://127.0.0.1:5501/iframe.html')
                document.body.appendChild(iframe)
            }else{
                document.createElement('crossFrmane').src='http://127.0.0.1:5501/iframe.html'
            }
        }
            

    </script>
</body>
</html>
代理页面 server1/iframe.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        window.onload=function(){
            console.log(top.sessionStorage.getItem('item'))

        }
    </script>
    
</body>
</html>
记录

在公司二次开发 ueditor 的时候遇到了跨域, 情况是当时想把 ueditor 的静态文件传到 cdn 文件目录下 ,项目访问直接在 index.html 或者 webpack 里配置引用, 富文本可以正常显示,但是涉及到弹框的 js 文件会报跨域的错误, 问题出在了 cdn 上的弹框内部 js 访问或操作当前页面中 DOM 导致的跨域, 预想的解决方法:配置 config 中的 iframeUrlMap,同是把 dialog 的文件拷贝在到线上目录下

v8

如何执行 JavaScript

将源码 (进行词法分析和语法分析)转为 AST(抽象语法树),然后解释器将其转为字节码, 如果该字节码-是热点代码,则编译器直接将其转为机器码(并把机器码保存下来,以备下次使用), 若不是热点代码,则由解释器 解释执行字节码 ----------JIT

JIT 与 AOT

JIT (Just-In-Time)--即时编译 ,边编译边运行 AOT (ahead of time)运行前进行编译

局域网分享代码方案

npm install -g keppler
keppler "My awesome project"

生成器示例

function *foo(){
    var x= yield 2;
    z++;
    var y = yield(x*z);
    console.log(x,y,z);
}

var z=1;
var it1 = foo();
var it2 = foo();

var val1 =it1.next().value;
console.log(val1)
// 2
var val2 = it2.next().value;
console.log(val2)
// 2
var val3 = it1.next(val2*10).value;
console.log(val3);
// x=20,z=2;40
var val4 = it2.next(val3*5).value;
// 600
console.log(val4);


it1.next(val4/2).value;
// 20 300 3
it2.next(val4/2).value;
// 200 300 3

vue slot 常用

查看
  • 父组件
<template v-slot:zt_add></template>
1
  • 子组件
<slot name="zt_add">
</slot>
1
2

事件冒泡与事件捕获

代码详情
<template>

  <div class="all-box">
    <div class="event_bubble_capture" contenteditable="false">
      <p>点击触发</p>
      <h4>
        addEventListener第三个参数默认为false,表示机制为事件冒泡,自下而上触发事件
      </h4>
      <div class="button-a" ref="button-a">
        a
        <div ref="button-b" class="button-b">b</div>
      </div>
      <p v-if="res1">输出为{{ res1.name }}</p>
      <h4>
        addEventListener第三个参数为true,表示机制为事件捕获,自上而下触发事件
      </h4>
      <div class="button-c" ref="button-c">
        c
        <div ref="button-d" class="button-d">d</div>
      </div>
      <p v-if="res2">输出为{{ res2.name }}</p>
    </div>
    <dialog_drag></dialog_drag>
  </div>
</template>

<script>
import { reactive } from "vue";
import dialog_drag from "../advanced/dialog_drag";
export default {
  setup() {
    const res1 = reactive({ name: "" });
    const res2 = reactive({ name: "" });
    return {
      res1,
      res2,
    };
  },
  components:{
    dialog_drag
  },
  mounted() {
    this.defineBubble();
    this.defineCapture();
  },
  methods: {
    defineBubble() {
      let that = this;
      let txt = "";
      let targetA = this.$refs["button-a"];
      targetA.addEventListener("click", function (e) {
        e.preventDefault();
        txt += "a";
        that.res1.name = txt.split("").join("=>");
        txt=''
      });
      let targetB = this.$refs["button-b"];
      targetB.addEventListener("click", function (e) {
        e.preventDefault();
        txt += "b";
        that.res1.name = txt.split("").join("=>");
      });
    },
    defineCapture() {
      let txt = "";
      let that = this;
      let targetA = this.$refs["button-c"];
      targetA.addEventListener(
        "click",
        function (e) {
          e.preventDefault();
          if(txt) txt=''
          txt += "c";
          that.res2.name = txt.split("").join("=>");
        },
        true
      );
      let targetB = this.$refs["button-d"];
      targetB.addEventListener(
        "click",
        function (e) {
          e.preventDefault();
          txt += "d";
          that.res2.name = txt.split("").join("=>");
          txt=''
        },
        true
      );
    },
  },
};
</script>

<style scoped lang="scss">
@import "~element-plus/dist/index.css";
.all-box{
  border: 2px solid;
  border-color:#666666 #00ff00 #888888 #0d84ff;
  padding: 20px;
  border-radius: 10px;
  &::after{
    content: ' ';
    display: block;
    width: 60px;
    height: 20px;
    background-color: #8c939d;
    transform: rotate(25deg) translate(-41%,181%);
  }
  &::before{
    content: ' ';
    display: block;
    width: 60px;
    height: 20px;
    background-color: #8c939d;
    transform: rotate(-25deg) translate(-50%,-181%);
  }
}
.event_bubble_capture {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  .button-a,
  .button-c {
    width: 100px;
    height: 100px;
    background-color: rgb(random(235), random(235), random(235));
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;

    color: #fff;
    font-size: 1.2em;
    font-weight: 500;
    cursor: pointer;
    .button-b,
    .button-d {
      width: 20px;
      height: 20px;
      text-align: center;
      line-height: 20px;
      background-color: rgb(random(235), random(235), random(235));
    }
    .button-d {
      background-color: rgb(random(235), random(235), random(235));
    }
  }
  .button-c {
    background-color: rgb(random(235), random(235), random(235));
  }
}






































 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 








































































vue3自定义指令

查看详情
<template>
    <div class="dialog-box">
        <el-input placeholder="placeholder" style="margin-top: 10vh;width: 20em" v-focus  v-model="inputString"></el-input>
        <el-tag type="success" v-heightLight="'10vh'">Tag 2</el-tag>
        <h4>自由移动块(自由度高,且设置了z-index)</h4>
        <div class="box" v-drag>
                <el-button type="primary" class="control"  @click="open">move me</el-button>
        </div>
    </div>
</template>

<script>
    import {reactive, ref, h} from 'vue'
    import {ElNotification} from 'element-plus'

    export default ({
        setup() {
            const dialogVisible = reactive({value: false});
            return {
                dialogVisible,
                inputString: ref('')
            }
        },
        methods: {
            handelClick() {
                this.dialogVisible.value = true
            },
            open(){
                ElNotification({
                    title: 'wow',
                    message: h('i', { style: 'color: teal'}, 'you clicked me'),
                })
            }
        },
        directives: {
            focus: {
                mounted(el) {
                    el.focus()
                }
            },
            heightLight: {
                beforeMount(el, binding, vNode) {
                    el.style.margin = binding.value;
                },
            },
            drag: {
                mounted(el) {
                    const dragDom = el.querySelector('.control');
                    dragDom.style.cursor = 'move';
                    dragDom.onmousedown = (e) => {

                        e.stopPropagation();
                        const disX = e.clientX- Number(el.style.left.replace('px',''));
                        const disY = e.clientY-Number(el.style.top.replace('px',''));

                        document.onmousemove = (e) => {//用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
                            let left = e.clientX;
                            let top = e.clientY;
                            el.style.left = left - disX  + 'px';
                            el.style.top = top - disY + 'px';
                        };
                        document.onmouseup = (e) => {
                            document.onmousemove = null;
                            document.onmouseup = null;
                        }
                    }
                }
            }
        }
    })
</script>
<style scoped>
    .dialog-box {

    }

    .box {
        width: 50px;
        height:50px;
        position: relative;
        z-index: 9999;
    }

    .box .control {
        width: 100px;
        height: 20px;
    }
</style>
  • 上述事件...和自定义指令写在下面的组件中

数组对象平铺后遍历处理属性结构的数据(自理的树状对象的垃圾处理方法)

查看详情
const data = [
    {
        id:1,
        children:[
            {
                id:2,
                children: [
                    {
                        id:3
                    }
                ],

            },
            {
                id:4,
                children:[
                    {
                        id:5
                    },{
                        id:6
                    }
                ]
            }
        ]
    },{
    id:7
    },
    {
    id:8,
        children: [
            {
        id:9,
            children: [{
            id:10
            }]
        }]
    }
]
let filterData = []
const getFilterData = (treeData,callback)=>{
    for(let i = 0;i<treeData.length;i++){
        let item = {}
        Object.defineProperty(item,`${treeData[i].id}`,{
            enumerable:true,
            configurable:true,
            set(v) {
                value = treeData[i].children
            },
            get() {
                return treeData[i].children
            }
        })
        filterData.push(item)
        if(treeData[i].children){
            getFilterData(treeData[i].children)
        }
    }
}
getFilterData(data);
console.log(filterData)

JS type coercion

你真的了解‘==’么open in new window

1=='1'
// true
1==='1'
// false
if(1){
  console.log(5)
}
// 5
if(0){
  console.log(5)
}
// 
-0 === +0
// true
Object.is(-0,+0)
// false
NaN === NaN
// false
object.is(NaN,NaN)
// true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

网页全屏/退出全屏

const doc = document;
const html = doc.documentElement;

const enter =
  html.requestFullscreen ||
  html.webkitRequestFullScreen ||
  html.mozRequestFullScreen ||
  html.msRequestFullscreen;

const exit =
  doc.exitFullscreen ||
  doc.webkitCancelFullScreen ||
  doc.mozCancelFullScreen ||
  doc.msExitFullscreen;

const enterFullScreen = () => {
  enter && enter.call(html);
};

const exitFullScreen = () => {
  exit && exit.call(doc);
};

export { enterFullScreen, exitFullScreen };

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

async/await

Last Updated: 6/21/2022, 1:47:29 AM
Contributors: ajn404, n-graymoon, mac_ajn404, ajn404