JavaScript snippets
Apr 2, 2014 · 9 分钟阅读

A simple canvas captcha

// 随机数
const randomNum = (min, max) => {
  return parseInt(Math.random() * (max - min) + min)
}
// 随机颜色
const randomColor = (min, max) => {
  const r = randomNum(min, max)
  const g = randomNum(min, max)
  const b = randomNum(min, max)
  return `rgb(${r},${g},${b})`
}

export default (el, state = {
  pool: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890', // 字符串
  width: 120,
  height: 40,
}) => {
  // 3.填充背景颜色,背景颜色要浅一点
  const ctx = el.getContext('2d')
  // 填充颜色
  ctx.fillStyle = randomColor(180, 230)
  // 填充的位置
  ctx.fillRect(0, 0, state.width, state.height)
  // 定义paramText
  let imgCode = ''
  // 4.随机产生字符串,并且随机旋转
  for (let i = 0; i < 4; i++) {
    // 随机的四个字
    const text = state.pool[randomNum(0, state.pool.length)]
    imgCode += text
    // 随机的字体大小
    const fontSize = randomNum(18, 40)
    // 字体随机的旋转角度
    const deg = randomNum(-30, 30)
    /*
    * 绘制文字并让四个文字在不同的位置显示的思路 :
    * 1、定义字体
    * 2、定义对齐方式
    * 3、填充不同的颜色
    * 4、保存当前的状态(以防止以上的状态受影响)
    * 5、平移translate()
    * 6、旋转 rotate()
    * 7、填充文字
    * 8、restore出栈
    * */
    ctx.font = fontSize + 'px Simhei'
    ctx.textBaseline = 'top'
    ctx.fillStyle = randomColor(80, 150)
    /*
    * save() 方法把当前状态的一份拷贝压入到一个保存图像状态的栈中。
    * 这就允许您临时地改变图像状态,
    * 然后,通过调用 restore() 来恢复以前的值。
    * save是入栈,restore是出栈。
    * 用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作。 restore:用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响。
    *
    * */
    ctx.save()
    ctx.translate(30 * i + 15, 15)
    ctx.rotate((deg * Math.PI) / 180)
    // fillText() 方法在画布上绘制填色的文本。文本的默认颜色是黑色。
    // 请使用 font 属性来定义字体和字号,并使用 fillStyle 属性以另一种颜色/渐变来渲染文本。
    // context.fillText(text,x,y,maxWidth);
    ctx.fillText(text, -15 + 5, -15)
    ctx.restore()
  }
  // 5.随机产生5条干扰线,干扰线的颜色要浅一点
  for (let i = 0; i < 5; i++) {
    ctx.beginPath()
    ctx.moveTo(randomNum(0, state.width), randomNum(0, state.height))
    ctx.lineTo(randomNum(0, state.width), randomNum(0, state.height))
    ctx.strokeStyle = randomColor(180, 230)
    ctx.closePath()
    ctx.stroke()
  }
  // 6.随机产生40个干扰的小点
  for (let i = 0; i < 40; i++) {
    ctx.beginPath()
    ctx.arc(randomNum(0, state.width), randomNum(0, state.height), 1, 0, 2 * Math.PI)
    ctx.closePath()
    ctx.fillStyle = randomColor(150, 200)
    ctx.fill()
  }
  return imgCode
}

A simple event emitter

export default {
  events: {},

  on(event, callback) {
    if (!this.events[event]) {
      this.events[event] = []
    }

    if (typeof callback === 'function') {
      this.events[event].push(callback)
    }
  },

  once(event, callback) {
    if (typeof callback === 'function') {
      const once = (...args) => {
        callback(...args)
        this.off(event, once)
      }
      this.on(event, once)
    }
  },

  emit(event, ...args) {
    if (this.events[event]) {
      this.events[event].forEach(callback => {
        callback(...args)
      })
    }
  },

  off(event, callback) {
    const callbacks = this.events[event]

    if (callbacks) {
      if (typeof callback === 'function') {
        this.events[event] = callbacks.filter(cb => cb.toString() !== callback.toString())
      } else {
        this.events[event] = null
      }
    }
  },
}

Use UMD to create a jQuery plugin

(function(factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['jquery'], factory);
  } else if (typeof module === 'object' && module.exports) {
    // Node/CommonJS
    module.exports = function(root, jQuery) {
      if (jQuery === undefined) {
        // require('jQuery') returns a factory that requires window to
        // build a jQuery instance, we normalize how we use modules
        // that require this pattern but the window provided is a noop
        // if it's defined (how jquery works)
        if (typeof window !== 'undefined') {
          jQuery = require('jquery');
        } else {
          jQuery = require('jquery')(root);
        }
      }
      factory(jQuery);
      return jQuery;
    };
  } else {
    // Browser globals
    factory(jQuery);
  }
}(function($) {
  $.fn.jqueryPlugin = function() {
    return true;
  };
}));

Lazy load images

function lazyLoad(offset = 0, selector = 'img[data-src]') {
  const load = () => {
    const imgs = [...document.querySelectorAll(selector + ':not(.loaded)')]

    imgs.forEach(img => {
      if (window.innerHeight - img.getBoundingClientRect().top + offset > 0) {
        img.src = img.dataset.src
        img.onload = () => img.classList.add('loaded')
      }
    })
  }

  load()
  window.addEventListener('scroll', load, false)
  window.addEventListener('resize', load, false)
}

Lazy load images with IntersectionObserver

function lazyLoad(offset = 0, selector = 'img[data-src]', root = null) {
  const interactSettings = {
    root: document.querySelector(root),
    rootMargin: `0px 0px ${offset}px 0px`
  }

  const onIntersection = (entries, observer) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target
        observer.unobserve(img)
        img.src = img.dataset.src
        img.onload = () => img.classList.add('loaded')
      }
    })
  }

  const observer = new IntersectionObserver(onIntersection, interactSettings)
  const imgs = [...document.querySelectorAll(selector + ':not(.loaded)')]
  imgs.forEach(img => observer.observe(img))
}

Throttle

const throttle = (fn, wait = 17) => {
  let lastTime = 0
  return function(...args) {
    let now = Date.now()

    if (now - lastTime >= wait) {
      lastTime = now
      fn.apply(this, args)
    }
  }
}

Debounce

const debounce = (fn, wait = 17) => {
  let timer = null
  return function(...args) {
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => {
      fn.apply(this, args)
    }, wait)
  }
}

Throttle and Debounce

const throttleDebounce = (fn, wait = 17) => {
  let lastTime = 0
  let timer = null

  return function(...args) {
    let now = Date.now()

    if (now - lastTime < wait) {
      if (timer) clearTimeout(timer)
      timer = setTimeout(() => {
        lastTime = now
        fn.apply(this, args)
      }, wait)
    } else {
      lastTime = now
      fn.apply(this, args)
    }
  }
}

Lodash cloneDeep

function cloneDeep(obj) {
  function isObject(o) {
    return (typeof o === 'object' || typeof o === 'function') && o !== null
  }

  if (!isObject(obj)) {
    return obj
  }

  let isArray = Array.isArray(obj)
  let newObj = isArray ? [...obj] : { ...obj }

  Reflect.ownKeys(newObj).forEach(key => {
    newObj[key] = isObject(obj[key]) ? cloneDeep(obj[key]) : obj[key]
  })

  return newObj
}

Format a Date

Date.prototype.format = function(format) {
  var o = {
    'M+': this.getMonth() + 1, // month
    'd+': this.getDate(), // day
    'h+': this.getHours(), // hour
    'm+': this.getMinutes(), // minute
    's+': this.getSeconds(), // second
    'q+': Math.floor((this.getMonth() + 3) / 3), // quarter
    'S': this.getMilliseconds() // millisecond
  }

  if (/(y+)/.test(format)) {
    format = format.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length));
  }

  for (var k in o) {
    if (new RegExp('(' + k + ')').test(format)) {
      format = format.replace(RegExp.$1, RegExp.$1.length == 1 ?
        o[k] :
        ('00' + o[k]).substr(('' + o[k]).length));
    }
  }

  return format;
};
new Date().format('yyyy-MM-dd hh:mm:ss'); // 2014-04-02 08:00:00

Set fetch body from an object

function setFetchBody(obj) {
  let str = ''
  if (!obj) return str

  let isFirstKey = true

  for (const key of Object.keys(obj)) {
    if (isFirstKey) {
      isFirstKey = false
      str += `${key}=${obj[key]}`
    } else {
      str += `&${key}=${obj[key]}`
    }
  }

  return str
}

Get items filter by including any one of other items

function getIncludedItems(arr1, arr2, prop) {
  return arr1.filter(function(el) {
    var included = false;

    for (var i = 0; i < arr2.length; i++) {
      var element = prop ? el[prop] : el;

      if (element.includes(arr2[i])) {
        included = true;
        break;
      }
    }

    return included;
  });
}
getIncludedItems(['as', 'bs', 'cs'], ['a', 'b']);
// ['as', 'bs']
getIncludedItems([{ domain: 'as.com' }, { domain: 'bs.com' }, { domain: 'cs.com' }], ['as', 'bs'], 'domain');
// [{ domain: 'as.com' }, { domain: 'bs.com' }]

Remove a certain item and return the rest

function getRestItems(arr, value, prop) {
  var rest = arr.slice();

  for (var i = 0; i < rest.length; i++) {
    if (prop && rest[i][prop] === value || !prop && rest[i] === value) {
      rest.splice(i, 1);
      break;
    }
  }

  return rest;
}
getRestItems([1, 2, { x: 3 }], 2); // [1, { x: 3}]
getRestItems([1, 2, { x: 3 }], 3, 'x'); // [1, 2]

Stop double-scrolling propagation

$('.scrollable').on('DOMMouseScroll mousewheel', function(ev) {
  var $this = $(this),
    scrollTop = this.scrollTop,
    scrollHeight = this.scrollHeight,
    height = $this.height(),
    delta = (ev.type == 'DOMMouseScroll' ?
      ev.originalEvent.detail * -40 :
      ev.originalEvent.wheelDelta),
    up = delta > 0;

  var prevent = function() {
    ev.stopPropagation();
    ev.preventDefault();
    ev.returnValue = false;
    return false;
  };

  if (!up && -delta > scrollHeight - height - scrollTop) {
    $this.scrollTop(scrollHeight);
    return prevent();
  } else if (up && delta > scrollTop) {
    $this.scrollTop(0);
    return prevent();
  }
});

Update URL query string

function updateQueryString(name, value) {
  var href = location.href;
  var search = location.search;
  var hash = location.hash;
  var query = getQueryString(name);
  var hasQuery = typeof query !== 'object';

  if (hasQuery) {
    return href.replace(name + '=' + query, name + '=' + value);
  } else {
    if (search) {
      return href.replace(search, search + '&' + name + '=' + value);
    } else {
      if (hash) {
        return href.replace(hash, '?' + name + '=' + value + hash);
      } else {
        return href + '?' + name + '=' + value;
      }
    }
  }
}

Get URL query string

function getQueryString(name, url) {
  var href = url ? url : window.location.href;
  var reg = new RegExp('[?&]' + name + '=([^&#]*)', 'i');
  var string = reg.exec(href);
  return string ? string[1] : null;
}

or:

function getQueryString(name, url) {
  var search = url ? url : window.location.search;
  return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(search)||[,""])[1].replace(/\+/g, '%20'))||null;
}

get the anchor:

function getAnchor(url) {
  return url ? url.split('#')[1] : window.location.hash.substring(1);
}

Remove HTML tags

function strip(html) {
  var tmp = document.createElement('DIV');
  tmp.innerHTML = html;
  return tmp.textContent || tmp.innerText || '';
}

with RegEx:

function strip(html) {
  return html.replace(/(<([^>]+)>)/ig, '');
}

with jQuery:

function strip(html) {
  return $(html).text();
}

Check for animation support

function browserSupportsCSSProperty(propertyName) {
  var elm = document.createElement('div');
  propertyName = propertyName.toLowerCase();

  if (elm.style[propertyName] != undefined)
    return true;

  var propertyNameCapital = propertyName.charAt(0).toUpperCase() + propertyName.substr(1),
    domPrefixes = 'Webkit Moz ms O'.split(' ');

  for (var i = 0; i < domPrefixes.length; i++) {
    if (elm.style[domPrefixes[i] + propertyNameCapital] != undefined)
      return true;
  }

  return false;
}

if (!browserSupportsCSSProperty('animation')) {
  // fallback…
}

Get the HTTP headers

var req = new XMLHttpRequest();
var headers = req.getAllResponseHeaders().toLowerCase();
req.open('GET', document.location, false);
req.send(null);
alert(headers);

with jQuery:

$.ajax({
  url: location.href
})
  .done(function(xhr) {
    console.log(xhr.getAllResponseHeaders(), xhr.getResponseHeader('Server'));
  });

Preload sound files

function preloadFiles(files, onComplete, onProgress) {
  var filesLoaded = 0,
    arr = [];

  for (var i = 0, len = files.length; i < len; i++) {
    arr[i] = new Audio();
    arr[i].addEventListener('canplaythrough', function() {
      filesLoaded++;
      if (filesLoaded === len && typeof onComplete === 'function') onComplete();
      if (typeof onProgress === 'function') onProgress(filesLoaded, len);
    }, false);
    arr[i].src = files[i];
    arr[i].load();
  };
}

A imitation of the localStorage object

if (!window.localStorage) {
  window.localStorage = {
    getItem: function(sKey) {
      if (!sKey || !this.hasOwnProperty(sKey)) {
        return null;
      }
      return unescape(document.cookie.replace(new RegExp("(?:^|.*;\\s*)" + escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*"), "$1"));
    },
    key: function(nKeyId) {
      return unescape(document.cookie.replace(/\s*\=(?:.(?!;))*$/, "").split(/\s*\=(?:[^;](?!;))*[^;]?;\s*/)[nKeyId]);
    },
    setItem: function(sKey, sValue) {
      if (!sKey) {
        return;
      }
      document.cookie = escape(sKey) + "=" + escape(sValue) + "; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/";
      this.length = document.cookie.match(/\=/g).length;
    },
    length: 0,
    removeItem: function(sKey) {
      if (!sKey || !this.hasOwnProperty(sKey)) {
        return;
      }
      document.cookie = escape(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
      this.length--;
    },
    hasOwnProperty: function(sKey) {
      return (new RegExp("(?:^|;\\s*)" + escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
    }
  };
  window.localStorage.length = (document.cookie.match(/\=/g) || window.localStorage).length;
}

set cookie:

function setCookie(name, value, days, path, domain) {
  var newDate = new Date();
  var days = isNaN(days) ? 365 : days;
  var expires;
  var cookie;

  newDate.setTime(newDate.getTime() + (days * 24 * 60 * 60 * 1000));
  expires = 'expires=' + newDate.toUTCString();
  cookie = name + '=' + value + ';' + expires + ';';
  if (path) cookie += 'path=' + path + ';';
  if (domain) cookie += 'domain=' + domain + ';';
  document.cookie = cookie;
};

get cookie:

function getCookie(name) {
  var name = name + '=';
  var cookies = document.cookie.split(';');
  var cookie;

  for (var i = 0; i < cookies.length; i++) {
    cookie = cookies[i];
    while (cookie.charAt(0) == ' ') cookie = cookie.substring(1);
    if (cookie.indexOf(name) == 0) return cookie.substring(name.length, cookie.length);
  }

  return '';
}

Get a shuffled copy of an array

var shuffle = function(arr) {
  var len = arr.length,
    shuffled = Array(len);

  for (var index = 0, rand; index < len; index++) {
    rand = Math.floor(Math.random() * (index + 1));
    if (rand !== index) shuffled[index] = shuffled[rand];
    shuffled[rand] = arr[index];
  }

  return shuffled;
};

Create dynamic variables

with eval():

eval('var variable' + i + '= arr[i]');

with window[]:

window['variable' + i] = arr[i];

Trigger click on an anchor

document.getElementsByTagName('a')[0].click();

with jQuery, you can use:

$('a')[0].click();
← Previous Post Next Post →

Ryun的博客
与其感慨路难行,不如马上出发。

atom css design git html javascript jekyll laravel life mac mobile optimization sublime tool vscode vue
mac

About

你好,❤朋友

这里是 Ryun 的博客 📝

📝记录了我学习 🔎的过程

作为一名前端攻城狮 🦁

希望能和大家一起 🔎

共同进步 🏃

🦁的特长:

  • HTML5
  • CSS3
  • JavaScript
  • Vue.js
  • 微信小程序
  • 熟练配合 Node.js、PHP 和 Laravel
  • 熟练使用各种开发和设计工具

🦁喜欢 🆒🆒的东西

对提升效率和美感的事物有兴趣 😋

欢迎 👏交流


see this hugo-theme-dream-ink