Giter VIP home page Giter VIP logo

daliy_knowledge's Introduction

2024, 治电十五年

求真 务实 坚韧 无畏, 寒冬无尽, 将亡治电

无情寒冬, 治电有情, 饱和制胜, 不饱必裁

🔎 Github 详情

klren0312

⚡ Github 统计

klren0312 klren0312

🔥 Github 连续提交记录

klren0312

💻 相关技术


HTML CSS Javacript node UBUNTU ESP32 STM32 Arduino

daliy_knowledge's People

Contributors

klren0312 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

daliy_knowledge's Issues

Vue组件库

webpack-mix配置

mix.js('resources/assets/vuejs/user/user.js', 'public/js');
mix.sass('resources/assets/vuejs/user/assets/theme/black.scss', 'public/css', {outputStyle: 'compressed'});
mix.sass('resources/assets/vuejs/user/assets/theme/white.scss', 'public/css', {outputStyle: 'compressed'});

// 生产环境
if (mix.inProduction()) {
  mix.version([]);
  mix.options({
    uglify: {
      parallel: true, // 加快构建速度
      sourceMap: false
    }
  });

  // 去除console.log
  mix.config.uglify.uglifyOptions = {
    compress: {
      warnings: false,
      drop_console: true,
      pure_funcs: ['console.log']
    }
  };
}

浏览器中JS获取相关宽高

网页可见区域宽:document.body.clientWidth 
网页可见区域高:document.body.clientHeight 
网页可见区域宽:document.body.offsetWidth (包括边线的宽) 
网页可见区域高:document.body.offsetHeight (包括边线的宽) 
网页正文全文宽:document.body.scrollWidth 
网页正文全文高:document.body.scrollHeight 
网页被卷去的高:document.body.scrollTop 
网页被卷去的左:document.body.scrollLeft 
网页正文部分上:window.screenTop 
网页正文部分左:window.screenLeft 
屏幕分辨率的高:window.screen.height 
屏幕分辨率的宽:window.screen.width 
屏幕可用工作区高度:window.screen.availHeight 
屏幕可用工作区宽度:window.screen.availWidth 


HTML精确定位:scrollLeft,scrollWidth,clientWidth,offsetWidth 
scrollHeight: 获取对象的滚动高度。 
scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离 
scrollTop:设置或获取位于对象最顶端和窗口中可见内容的最顶端之间的距离 
scrollWidth:获取对象的滚动宽度 
offsetHeight:获取对象相对于版面或由父坐标 offsetParent 属性指定的父坐标的高度 
offsetLeft:获取对象相对于版面或由 offsetParent 属性指定的父坐标的计算左侧位置 
offsetTop:获取对象相对于版面或由 offsetTop 属性指定的父坐标的计算顶端位置 
event.clientX 相对文档的水平座标 
event.clientY 相对文档的垂直座标 
event.offsetX 相对容器的水平坐标 
event.offsetY 相对容器的垂直坐标 
document.documentElement.scrollTop 垂直方向滚动的值 
event.clientX+document.documentElement.scrollTop 相对文档的水平座标+垂直方向滚动的

git修改分支名

修改本地分支名

git branch -m 旧分支名 新分支名

删除远程旧分支

git push origin :旧分支

将新分支push

git push origin 新分支

JS给数字补零

function (num, len) {
  return (Array(len).join('0') + num).slice(-len)
}

image

echarts柱状图

var taskChartOpt = {
      color: ['#d5a200', '#10d092', '#4cc3cb', '#716cc5', '#ef5350'],
      tooltip: {
        trigger: 'axis',
        axisPointer: { // 坐标轴指示器,坐标轴触发有效
          type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
        },
        formatter: function (params) {
          return params[0].name + '<br>' + params[0].marker + params[0].seriesName + ': ' + byteFormat(params[0].value)
        }
      },
      grid: {
        left: '3%',
        right: '4%',
        bottom: '0',
        containLabel: true
      },
      xAxis: {
        type: 'category',
        data: [],
        axisLine: {
          show: false
        },
        axisTick: {
          show: false
        },
        axisLabel: {
          color: '#5182c1',
          interval: 0,
          rotate: 20
        }
      },
      yAxis: {
        type: 'value',
        axisLine: {
          show: false,
        },
        axisTick: {
          show: false
        },
        splitLine: {
          lineStyle: {
            type: 'dashed',
            color: '#1f385e5f'
          }
        },
        axisLabel: {
          color: '#5182c1',
        }
      },
      series: [{
        name: '空间占用',
        type: 'bar',
        itemStyle: {
          normal: {
            color: function (params) {
              var colorList = ['#d5a200', '#10d092', '#4cc3cb', '#716cc5', '#ef5350'];
              return colorList[params.dataIndex];
            }
          }
        },
        barWidth: '30%',
        data: []
      }]
    };

git log --pretty=format 相关参数

git log --pretty=format参数

选项 说明
%H 提交对象(commit)的完整哈希字串
%h 提交对象的简短哈希字串
%T 树对象(tree)的完整哈希字串
%t 树对象的简短哈希字串
%P 父对象(parent)的完整哈希字串
%p 父对象的简短哈希字串
%an 作者(author)的名字
%ae 作者的电子邮件地址
%ad 作者修订日期(可以用 --date= 选项定制格式)
%ar 作者修订日期,按多久以前的方式显示
%cn 提交者(committer)的名字
%ce 提交者的电子邮件地址
%cd 提交日期
%cr 提交日期,按多久以前的方式显示
%s 提交说明

使用方法

git log --pretty=format:"%s"

参考资料

Git-基础-查看提交历史

Vue项目升级问题

一 Element 1.x => Element 2.x

1.scope 改为 slot-scope

2.引入ele的css名称变了

import 'element-ui/lib/theme-default/index.css'

改为

import 'element-ui/lib/theme-chalk/index.css'

二 vue-cli => vue-cli3

1. 报错[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.

原因: vue.config.js中添加别名

configureWebpack: {
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js' 
    }
  }
}

2. 新的编译会比老版严格

  • 老代码里一些没定义的变量, 方法都报错了
  • v-for没有key也报错了

3. checkbox全选事件

https://element.eleme.cn/2.8/#/zh-CN/component/checkbox#indeterminate-zhuang-tai

<el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>

handleCheckAllChangev1.x中返回的是事件, 而v2.x中返回的是全选后的数组

3. TimePicker

v1.x没有value-format

puppeteer镜像

npm user

npm config set registry https://registry.npm.taobao.org
npm config set disturl https://npm.taobao.org/dist
npm config set puppeteer_download_host https://npm.taobao.org/mirrors

yarn user

yarn config set registry https://registry.npm.taobao.org
yarn config set disturl https://npm.taobao.org/dist
yarn config set puppeteer_download_host https://npm.taobao.org/mirrors

vue页面刷新

issue讨论

https://github.com/vuejs/vue-router/issues/296

方法一: 使用一个重定向页面

1.搞个重定向页面

<script>
export default {
  beforeCreate() {
    const { params, query } = this.$route
    const { path } = params
    this.$router.replace({ path: '/' + path, query })
  },
  render: function(h) {
    return h() // avoid warning message
  }
}
</script>

2.刷新

// 手动重定向页面到 '/redirect' 页面
const { fullPath } = this.$route
this.$router.replace({
  path: '/redirect' + fullPath
})

方法二: 使用provide/inject

1.App.vue定义

<template>
  <div id="app">
    <router-view v-if="isRouterAlive"></router-view>
  </div>
</template>
<script>
export default {
  name: 'App',
  provide() {
    return {
      reload: this.reload
    }
  },
  data() {
    return {
      isRouterAlive: true
    }
  },
  methods: {
    reload() {
      this.isRouterAlive = false
      this.$nextTick(_ => {
        this.isRouterAlive = true
      })
    }
  }
}
</script>

2.使用

<script>
export default {
  inject: ['reload']
}
</script>

在方法中调用即可this.reload()

导航栏滚动变色

    function onScroll() {
      var scrollH = $('#carousel-container').height()
      var windowH = $(window).scrollTop()
      if (windowH > scrollH) {
        $('.navbar-default').addClass('active')
      } else {
        $('.navbar-default').removeClass('active')
      }
    }
    window.addEventListener('scroll', onScroll, false);

JS函数节流(两种方法)

第一种

通过每次对比当前时间 与 基本时间加上延迟时间的大小

  • 若基本事件加上延时要小于当前时间, 则调用方法, 并将基本时间设置成当前时间
  • 若基本事件加上延时要大于当前时间, 说明还在节流时间内, 则不调用方法
/**
 * 函数节流
 * @param {Function} fn 函数
 * @param {Number} delay 延时
 */
function throttle(fn, delay) {
  var baseTime = 0
  return function () {
    var currentTime = Date.now()
    if (baseTime + delay <= currentTime) {
      baseTime = currentTime
      fn.apply(this, arguments)
    }
  }
}

第二种

通过判断是否存在timeout序号, 来判断是否处于节流时间, 但是这会导致第一次执行也会有delay时间的延时

/**
 * 函数节流
 * @param {Function} fn 函数
 * @param {Number} delay 延时
 * @param {Object} context 上下文
 */
function throttle (fn, delay = 100, context = this) {
  let timeout = null
  let fnArgs = null
  return (...args) => {
    if (!timeout) {
      fnArgs = args
      timeout = setTimeout(() => {
        fn.apply(context, fnArgs)
        timeout = null
      }, delay)
    }
  }
}

vuex覆盖state

const mutations = {
  EDIT (state, obj) {
    for(var i in obj){
      state[i] = obj[i]  // 覆盖
    }
  }
}

无限极树遍历

toTree(data) {
  data.forEach((item) => {
    delete item.children
  })
  this.treeObj = {}
  let map = {}
  data.forEach((item) => {
    map[item.Id] = item
  })
  this.treeObj = map
  let val = []
  data.forEach((item) => {
    let parent = map[item.ParentId]
    if (parent) {
      (parent.children || ( parent.children = [] )).push(item)
    } else {
      item.children = []
      val.push(item)
    }
  })
  return val
}

JS在光标位置插入元素

function insertContent(content) {
      if (!content) { // 如果插入的内容为空则返回
        return
      }
      let sel = null
      if (document.selection) { // IE9以下
        sel = document.selection
        sel.createRange().pasteHTML(content)
      } else {
        sel = window.getSelection()
        console.log(sel)
        if (sel.rangeCount > 0) {
          let range = sel.getRangeAt(0) // 获取选择范围
          range.deleteContents() // 删除选中的内容
          let el = document.createElement("div") // 创建一个空的div外壳 
          el.innerHTML = content // 设置div内容为我们想要插入的内容。
          let frag = document.createDocumentFragment() // 创建一个空白的文档片段,便于之后插入dom树
          let node = el.firstChild
          let lastNode = frag.appendChild(node)
          range.insertNode(frag) // 设置选择范围的内容为插入的内容
          let contentRange = range.cloneRange() // 克隆选区
          contentRange.setStartAfter(lastNode) // 设置光标位置为插入内容的末尾
          contentRange.collapse(true) // 移动光标位置到末尾
          sel.removeAllRanges() // 移出所有选区
          sel.addRange(contentRange) // 添加修改后的选区
        }
      }
    }
  }

Electron中使用puppeteer问题, chrome路径问题

正常开发模式, 会在安装puppeteer时安装chromium
但是编译打包后会漏掉chromium
所以我们可以改用puppeteer-core, 然后自己配置路径

export default function getChromePath () {
  if (process.platform === 'win32') {
    return 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe'
  } else {
    return '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
  }
}

使用的时候

const puppeteer = require('puppeteer-core')
... ...
await puppeteer.launch({
  headless: true,
  executablePath: this.getChromePath()
})

参考: https://github.com/loukaspd/puppeteer-electron-quickstart/blob/621248a4f4/src/lib/puppeteer-wrapper.js

Vue项目访问白屏时加载动画

1. 加载动画

https://epic-spinners.epicmax.co/#/

2. 在index.html中引入动画

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <style>
      .loading-spinner {
        display: flex;
        justify-content: center;
        align-items: center;
        width: 100%;
        height: 100vh;
      }
      .orbit-spinner, .orbit-spinner * {
        box-sizing: border-box;
      }

      .orbit-spinner {
        height: 55px;
        width: 55px;
        border-radius: 50%;
        perspective: 800px;
      }

      .orbit-spinner .orbit {
        position: absolute;
        box-sizing: border-box;
        width: 100%;
        height: 100%;
        border-radius: 50%;
      }

      .orbit-spinner .orbit:nth-child(1) {
        left: 0%;
        top: 0%;
        animation: orbit-spinner-orbit-one-animation 1200ms linear infinite;
        border-bottom: 3px solid #009688;
      }

      .orbit-spinner .orbit:nth-child(2) {
        right: 0%;
        top: 0%;
        animation: orbit-spinner-orbit-two-animation 1200ms linear infinite;
        border-right: 3px solid #009688;
      }

      .orbit-spinner .orbit:nth-child(3) {
        right: 0%;
        bottom: 0%;
        animation: orbit-spinner-orbit-three-animation 1200ms linear infinite;
        border-top: 3px solid #009688;
      }

      @keyframes orbit-spinner-orbit-one-animation {
        0% {
          transform: rotateX(35deg) rotateY(-45deg) rotateZ(0deg);
        }
        100% {
          transform: rotateX(35deg) rotateY(-45deg) rotateZ(360deg);
        }
      }

      @keyframes orbit-spinner-orbit-two-animation {
        0% {
          transform: rotateX(50deg) rotateY(10deg) rotateZ(0deg);
        }
        100% {
          transform: rotateX(50deg) rotateY(10deg) rotateZ(360deg);
        }
      }

      @keyframes orbit-spinner-orbit-three-animation {
        0% {
          transform: rotateX(35deg) rotateY(55deg) rotateZ(0deg);
        }
        100% {
          transform: rotateX(35deg) rotateY(55deg) rotateZ(360deg);
        }
      }
    </style>
  </head>
  <body>
    <div class="loading-spinner">
      <div class="orbit-spinner">
        <div class="orbit"></div>
        <div class="orbit"></div>
        <div class="orbit"></div>
      </div>
    </div>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

3. 页面加载完成, 在App.vue中将加载动画删除

... ...
 created () {
    try {
      document.body.removeChild(document.getElementById('loading-spinner'))
    } catch (e) {
    }
  },
... ...

JS正则匹配括号内的内容, 除去括号

例子字符串

testestetaet<0,1,5,1,False,False>ewfafewf

需要获取

<>中的0,1,5,1,False,False

正则表达式

/\<([^)]+>\>/

使用

`testestetaet<0,1,5,1,False,False>ewfafewf`.match(/\<([^>]+)\>/)[1]

image

分解

/ \< ( [^>] + ) \> /

  1. \< : 匹配前括号
  2. ( : 捕获括号开始
  3. [^>]+: 匹配除了>的其他字符
  4. ) : 捕获括号结束
  5. \> : 匹配后括号

参考资料

JS复制

先创建一个textarea, 绝对定位到看不到的地方, 将需要复制的字符串放入, 并选中, 使用document.execCommand('copy')复制文本, 然后删除textarea

const copyToClipboard = str => {
  const el = document.createElement('textarea');
  el.value = str;
  el.setAttribute('readonly', '');
  el.style.position = 'absolute';
  el.style.left = '-9999px';
  document.body.appendChild(el);
  const selected =
    document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false;
  el.select();
  document.execCommand('copy');
  document.body.removeChild(el);
  if (selected) {
    document.getSelection().removeAllRanges();
    document.getSelection().addRange(selected);
  }
};

参考资料:

JS深拷贝

学习一下vuex的deepCopy源码
https://github.com/vuejs/vuex/blob/dev/src/util.js#L22

注释

我直接把第29行用的find函数放到里面了, 这样好看一点

/**
 * 深拷贝
 * @param {*} obj 拷贝对象(object or array)
 * @param {*} cache 缓存数组
 */
function deepCopy (obj, cache = []) {
  // typeof [] => 'object'
  // typeof {} => 'object'
  if (obj === null || typeof obj !== 'object') {
    return obj
  }
  // 如果传入的对象与缓存的相等, 则递归结束, 这样防止循环
  /**
   * 类似下面这种
   * var a = {b:1}
   * a.c = a
   * 资料: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value
   */
  const hit = cache.filter(c => c.original === obj)[0]
  if (hit) {
    return hit.copy
  }

  const copy = Array.isArray(obj) ?  [] :   {}
  // 将copy首先放入cache, 因为我们需要在递归deepCopy的时候引用它
  cache.push({
    original: obj,
    copy
  })
  Object.keys(obj).forEach(key => {
    copy[key] = deepCopy(obj[key], cache)
  })

  return copy
}

学习

1.28行if obj is hit, it is in circular structure

一开始没理解什么是循环结构, 后来在MDN的一个文章中看到了, 就类似于下图这样的循环结构
image

2.typeof方法对应的是基本类型

检测数组和对象返回都是'object'
image

注: 如果要区分数组和对象, 使用使用 Array.isArray 或者 Object.prototype.toString.call

3.基本原理

就是使用递归对数组或者对象进行每一项的复制, 数组当做对象时, 下标即为key
image

深拷贝的另一个简单的方法

直接使用JSON.parse(JSON.stringify(Object))来进行
缺点: 如果对象或者数组里有函数什么的, 就会出问题啦
image

当然对于函数可以使用JSON.stringify()和JSON.parse()的第二个参数进行转换

function stringifyRep(key, value) {
  if (typeof value === "function") {
    return `${value}`;
  }
  return value;
}
function parseRep(key, value) {
  return eval(value);
}
var a = {
  b: () => 1 + 1
}
var aa = JSON.parse(JSON.stringify(a, stringifyRep), parseRep)

image.png

最后

更多小方法, 可以查看https://github.com/klren0312/daliy_knowledge/issues

Vuex简化模块导入

webpack文档: https://webpack.js.org/guides/dependency-management/#requirecontext

import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'

Vue.use(Vuex)

// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context('./modules', false, /\.js$/)

// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
  // set './app.js' => 'app'
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
  const value = modulesFiles(modulePath)
  modules[moduleName] = value.default
  return modules
}, {})

const store = new Vuex.Store({
  modules,
  getters
})

export default store

Element Tree选中节点后, 生成选中的树

    getSuperResultTree() {
      // 初始化结果树
      this.treeResultData = JSON.parse(JSON.stringify(this.defaultResultData))
      const arr = JSON.parse(JSON.stringify(this.$refs.leftTree.getCheckedNodes(true)))
      this.useTotal = arr.length // 计入高级搜索的分类数, 用于判断结束
      // 将选择的分类相关节点遍历到指定位置
      arr.forEach(v => {
        let i1 = this.treeResultData.findIndex(t1 => {
          return t1.id === v.res[0]
        })
        let i2 = this.treeResultData[i1].children.findIndex(t2 => {
          return t2.data_type === v.res[1]
        })
        this.treeResultData[i1].children[i2].children.push(v)
      })
      // 清除未用节点
      this.treeResultData = this.treeResultData.filter(v => {
        v.children = v.children.filter(u => {
          return u.children.length !== 0
        })
        return v.children.length !== 0
      })
      console.log('高级结果树', this.treeResultData)
    }

Nodejs消息队列库

Feature Bull Kue Bee Agenda
Backend redis redis redis mongo
Priorities
Concurrency
Delayed jobs
Global events
Rate Limiter
Pause/Resume
Sandboxed worker
Repeatable jobs
Atomic ops
Persistence
UI
REST API
Optimized for Jobs / Messages Jobs Messages Jobs

JS将图片转为base64

function ImgToBase64(file, maxLen, callBack) {
  var img = new Image();

  var reader = new FileReader();//读取客户端上的文件
  reader.onload = function () {
      var url = reader.result;//读取到的文件内容.这个属性只在读取操作完成之后才有效,并且数据的格式取决于读取操作是由哪个方法发起的.所以必须使用reader.onload,
      img.src = url;//reader读取的文件内容是base64,利用这个url就能实现上传前预览图片
  };
  img.onload = function () {
      img.width = maxLen;
      img.height = maxLen;
      //生成canvas
      var canvas = document.createElement("canvas");
      var ctx = canvas.getContext("2d");
      canvas.width = img.width;
      canvas.height = img.height;
      ctx.drawImage(img, 0, 0, img.width, img.height);
      var base64 = canvas.toDataURL('image/jpeg', 0.9);
      callBack(base64);
  };
  reader.readAsDataURL(file);
}

参考资料:

JS创建对象, 不继承对象属性

var obj = Object.create(null)

若要使用Object的相关方法, 可以使用call, apply, bind

obj.test = 'ttt'
obj.hasOwnProperty('test') // => Uncaught TypeError: obj.hasOwnProperty is not a function
Object.hasOwnProperty.call(obj, 'test') // => true
Object.hasOwnProperty.apply(obj, ['test']) // => true
Object.hasOwnProperty.bind(obj)('test') // => true

IE报错 [vuex] vuex requires a Promise polyfill in this browser.

image

使用官方文档提供的方法解决

内容如下

你可以通过 CDN 将其引入:

<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.js"></script>

然后 window.Promise 会自动可用。

如果你喜欢使用诸如 npm 或 Yarn 等包管理器,可以按照下列方式执行安装:

npm install es6-promise --save # npm
yarn add es6-promise # Yarn

或者更进一步,将下列代码添加到你使用 Vuex 之前的一个地方:

import 'es6-promise/auto'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.