violet0sea / note

can not open gist, so write here
0 stars 0 forks source link

small funcs #17

Open violet0sea opened 6 years ago

violet0sea commented 6 years ago

获取浏览器的query

function getQuery() {
    var search = location.search;
    if(!search) {
        return;
    }
    if(search) {
        search = search.slice(1);
    }

    var list = search.split('&');
    var result = {}, len = list.length;

    while(len--) {
        var temp = list[len].split("=");

        result[decodeURIComponent(temp[0])] = decodeURIComponent(temp[1]);

    }
    return result;
}
violet0sea commented 6 years ago

生成随机的Id(0-9a-zA-Z)

function randomId(len = 4) {
    let str = "";
    const arr =  ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];

    while(len--) {
        const range = Math.floor(Math.random() * 62);
        str += arr[range];
    }

    return str;
}
violet0sea commented 6 years ago

timestamp时间格式化MM/DD/YYYY

/**
 * 一位日期补0
 */

 function format2Two(number) {
    let str = '' + number;
    if(str.length === 1) {
        str = '0' + str;
    }
    return str;
}

/**
 * 时间格式化 MM/DD/YYYY
 */

export function getFormatDate(timeStamp) {
    const date = new Date(timeStamp);
    const year = date.getFullYear();
    const month = format2Two(date.getMonth() + 1);
    const day = format2Two(date.getDate());
    return `${month}/${day}/${year}`;
}
violet0sea commented 6 years ago

H5唤起app

          var startTime = new Date();
          window.location.href = '<scheme>';  

          var timer = setTimeout(function() {
            if(new Date() - startTime < 2000) {

              window.location.href = ‘<download page url>’
            } else {
              clearTimeout(timer);
            }
          });
violet0sea commented 5 years ago

React 使用html2canvas将网页绘制为图片


<button id="save_image_locally" onClick={this.dowload}>download img</button>

  dowload() {
    const dom = document.querySelector('.App-header');
    html2canvas(dom)
      .then(canvas => {
        var a = document.createElement('a');
        a.href = canvas.toDataURL("image/jpeg"); // can be png 
        a.download = 'download.jpg';
        a.click();
      })

  }
violet0sea commented 5 years ago

React upload file function

1.已formData binary格式发送

  upload(e) {
      const file = e.target.files[0];
      console.log(file);
      const formData = new FormData();
      formData.append('file', file);
      axios.post(<upload url>, formData)
  }

2.已base64的格式发送

    upload =(e)=> {
        e.preventDefault();
        let reader = new FileReader();
        let file = e.target.files[0];

        reader.onloadend = () => {
            let params={};
            params.pic = reader.result;
            axios.post(<upload url>, params)
        }
        if (file && file.type.match('image.*')) {
            reader.readAsDataURL(file)
        }
    }
violet0sea commented 5 years ago

stackoverflow上的deepClone,神奇

function deepClone(obj, hash = new WeakMap()) {
    if(Object(obj) !== obj || obj instanceof Function) {
        return obj;
    }

    if(hash.has(obj)) {
        return hash.get(obj);
    }

    let result;
    try {
        result = new obj.constructor();
    } catch(err) {
        result = Object.getPrototypeOf(obj);
    }

    hash.set(obj, result);
    return Object.assign(result, ...Object.keys(obj).map(
        key => ({[key]: deepClone(obj[key], hash)})
    ));
}
violet0sea commented 5 years ago

解决浏览器关闭时发送请求的问题 产品需求时编辑时发送一个正在编辑的状态给服务端,防止其他人同时修改,修改完毕或者取消时解除状态,大部分情况下这样的逻辑都是可行的。但是,如果处于编辑状态时关闭浏览器会如何?目前就浏览器的形为来看,如果直接发送ajax请求,由于是异步的会被取消。那有没有什么方法可以在浏览器关闭前发送请求,其实并不关心请求的响应,仅仅只是发送请求,也适用于数据上报的情形 解决方案

1. 如果要发送get请求
function sendQuery(params){
  const img = new Image();
  const path = '/content/cms/doc/action/edit';
  const {query} = params;
  img.src = `${path}?${query}`;
}
2.如果发送post请求, navigator.sendBeacon的第二个参数时请求体
sendQuery({query: `docId=${'c60e0704'}&flag=0`})
function sendBeacon(params) {
  const path = '/content/cms/doc/action/edit';
  const {query} = params;
  navigator.sendBeacon(`${path}?${query}`, {});
}
sendBeacon({query: `docId=${'c60e0704'}&flag=0`})
violet0sea commented 5 years ago

debounce and throttle

function debounce(fn, wait, immediately) {
  let timer;
  return function debouncedFun() {
    const callNow = immediately && !timer;

    if (callNow) {
      fn.apply(this, arguments);
    }

    if (timer) {
      clearTimeout(timer);
    }

    timer = setTimeout(() => {
      timer = null;
      fn.apply(this, arguments);
    }, wait);
  };
}

function throttle(fn, wait) {
  let lastTime;
  let timer;

  return function() {
    const now = +new Date();
    // 每次触发时需要更新剩余时间防止两次执行的间隔远大于wait
    const remaining = lastTime ? lastTime + wait - now : 0;
    clearTimeout(timer);

    if (remaining > 0) {
      timer = setTimeout(() => {
        lastTime = now;
        fn.apply(this, arguments);
      }, remaining);
    } else {
      lastTime = now;
      fn.apply(this, arguments);
    }
  };
}
violet0sea commented 5 years ago

延时队列

function Task() {
  var cache = [];
  var index = 0;

  var add = function (fn, time) {
    cache.push({ fn, time });
  };

  var run = async function () {
    const task = cache[index++];
    if (!task) {
      index = 0;
      return;
    }
    const res = sleep(task.fn, task.time);
    res.then(fn => {
      fn();
      run();
    })

  };

  return { add, run };
}

function sleep(fn, time) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, time, fn)
  })
}
var t1 = new Task()
t1.add(() => { console.log(100) }, 100)
t1.add(() => { console.log(1000) }, 1000)
t1.add(() => { console.log(2000) }, 2000)
t1.run()
function Task() {
  var list = [];
  var index = 0;

  var add = function (fn, time) {
    list.push(asyncTask(fn, time));
  };

  var run = function () {
    var currentFun = list[index];
    typeof currentFun === 'function' && currentFun(next);
  };

  var next = function() {
    if(index >= list.length - 1) {
      index = 0
      return;
    }

    var currentFun = list[++index];
    typeof currentFun === 'function' && currentFun(next);
  }

  return { add, run };
}

function asyncTask(fn, wait) {
  return function(next) {
    setTimeout(() => {
      fn();
      next();
    }, wait);
  }
}

var t1 = new Task()
t1.add(() => { console.log(100) }, 100)
t1.add(() => { console.log(1000) }, 1000)
t1.add(() => { console.log(2000) }, 2000)
t1.run()
violet0sea commented 5 years ago

表单校验

/**
 * 表单校验策略
 */
var validStrategy = {
  nonEmptyString(str, errorMsg) {
    if (str === '') {
      return errorMsg
    }
  },
  nonEmptyArray(arr, errorMsg) {
    if (Array.isArray(arr) && arr.length > 0) {
      return errorMsg
    }
  },
  stringMaxLength(str, maxLength, errorMsg) {
    if (str.length > maxLength) {
      return errorMsg
    }
  }
}

/**
 * 校验类
 * 返回add & start
 * add(value, rules) // value: 校验值 rules[{strategy, payload}]
 * strategy可以传递function,接收value作为参数,可以针对当前值做自定义的校验规则
 * 比如当前值依赖另一个值是否存在
 * payload 里面必须传递errorMsg作为失败的返回,其他字段可以自定义用于校验策略里的验证
*/
function Validator() {
  let validatorList = []

  function add(value, rules) {
    for (var i = 0; i < rules.length; i++) {
      const rule = rules[i]
      const { strategy, payload } = rule

      if (typeof strategy === 'string') {
        normalCheck(value, strategy, payload)
      }

      if (typeof strategy === 'function') {
        customFunction(value, strategy, payload)
      }
    }
  }

  function normalCheck(value, strategy, payload) {
    const validFun = validStrategy[strategy]

    if (typeof validFun !== 'function') {
      throw new Error(`表单校验的strategy[${strategy}]不存在`)
    }

    validatorList.push(function() {
      return validFun.apply(null, [value, payload])
    })
  }

  function customFunction(value, isValidFun, payload) {
    const boundFun = function() {
      if (!isValidFun(value)) {
        return payload.errorMsg
      }
    }
    validatorList.push(boundFun)
  }

  function start() {
    for (var i = 0, len = validatorList.length; i < len; i++) {
      const validFun = validatorList[i]
      const errorMsg = validFun()

      if (errorMsg) {
        return errorMsg
      }
    }
  }

  return {
    add,
    start
  }
}
var valid = new Validator()
var checkedValue = 'long'
valid.add(checkedValue, [
  {
    strategy: 'nonEmptyString',
    payload: {
      errorMsg: 'no empty'
    }
  },
  {
    strategy: 'stringMaxLength',
    payload: {
      maxLength: 5,
      errorMsg: 'beyound max length of 5'
    }
  },
  {
    strategy: function(value) {
      if (value.indexOf('https://') === -1) {
        return false
      }

      return true
    },
    payload: {
      errorMsg: 'function check fail'
    }
  }
])

var errorMsg = valid.start()
if (errorMsg) {
  console.log(errorMsg)
}
violet0sea commented 5 years ago
function MyPromise(cb) {
  this._value;
  this._status = 'pending';
  this.successCbs = [];
  this.failureCbs = [];

  var self = this;

  function resolveFun(value) {
    self._value = value;
    self._status = 'fulfilled';

    setTimeout(() => {
      self.successCbs.forEach(fn => fn(value));
    }, 0);
  }

  function rejectFun(err) {
    self._value = err;
    self._status = 'fulfilled';

    setTimeout(() => {
      self.failureCbs.forEach(fn => fn(err));
    }, 0)
  }

  cb(resolveFun, rejectFun);
}

MyPromise.prototype.then = function(fulfilled, rejected) {
  if(this._status === 'pending') {
    if(typeof fulfilled === 'function') {
      this.successCbs.push(fulfilled);
    }

    if(typeof rejected === 'function') {
      this.failureCbs.push(rejected);
    }
  } else if(this._status === 'fulfilled') {
    fulfilled(this._value);
  } else {
    rejected(this._value);
  }

}

var pp = new MyPromise((res, rej) => {
  setTimeout(() => {
    res(100)
  }, 1000)
})

pp.then(val => {
  console.log('succ', val)
}, err => {
  console.log('err', err)
})
violet0sea commented 5 years ago

IntersectionObserver 实现image lazy load

    const config = {
      rootMargin: '0px 0px 50px 0px',
      threshold: 0
    };

    // register the config object with an instance
    // of intersectionObserver
    let observer = new IntersectionObserver(function (entries, self) {
      // iterate over each entry
      entries.forEach(entry => {
        // process just the images that are intersecting.
        // isIntersecting is a property exposed by the interface
        if (entry.isIntersecting) {
          // custom function that copies the path to the img
          // from data-src to src
          preloadImage(entry.target);
          // the image is now in place, stop watching
          self.unobserve(entry.target);
        }
      });
    }, config);
    function preloadImage(ele) {
      const src = ele.getAttribute('data-src');
      ele.src = src;
    };
    const imgs = document.querySelectorAll("img[’data-src‘]");
    imgs.forEach(img => {
      observer.observe(img);
    });