striveDJiang 8 年 前
コミット
2f1e1d49f2

+ 0 - 21
Node.js/test/createServer.js

@@ -1,21 +0,0 @@
-let http = require('http');
-let url = require('url');
-let util = require('util');
-
-// 使用http模块中的createServer()方法创建服务器并返回一个实例对象,该实例对象有一个listen()方法,通过request,response参数来接收和响应数据
-let server = http.createServer((req, res) => {
-  // 设置编码及响应头部信息
-  // res.writeHead(200,{"Content-Type": "text/plain; charset=utf-8"});
-  res.statusCode = 200;
-  res.setHeader("Content-Type", "text/plain; charset=utf-8");
-  // 响应结束,向客户端发送响应数据
-  // 通过req.url拿到浏览器端访问的地址
-  // url模块中的parse()方法解析一个URL字符串并返回一个URL对象
-  // util模块中的inspect()方法返回object的字符串表示,主要用于调试
-  res.end(util.inspect(url.parse(req.url)));
-});
-
-// 使用server实例对象的listen方法指定这个HTTP服务器监听的端口号为3000
-server.listen(3000, '127.0.0.1', () => {
-  console.log("服务器已经运行,请打开浏览器,输入:http://127.0.0.1:3000/ 来进行访问")
-});

+ 0 - 23
Node.js/test/httpGet.js

@@ -1,23 +0,0 @@
-let http = require('http');
-let util = require('util');
-
-// 通过http模拟请求访问第三方接口
-http.get("http://www.imooc.com/u/card", (res) => {
-  // 定义一个data变量,用于暂存接收到的数据
-  let data = '';
-  // 通过res的data事件监听函数,每当接收到数据,就累加到data变量中
-  res.on('data', (chunk) => {
-    data += chunk;
-  });
-  // 在end事件触发后,通过JSON.parse将data变量转换为JSON对象,然后返回给客户端调用
-  res.on('end', () => {
-    try {
-      let result = JSON.parse(data);
-      console.log("result:" + util.inspect(result))
-    } catch (e) {
-      console.error(e.message);
-    }
-  }).on('error', (e) => {
-    console.error(`错误: ${e.message}`);
-  });
-});

+ 0 - 17
Node.js/test/index.html

@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-
-<head>
-    <meta charset="UTF-8">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <meta http-equiv="X-UA-Compatible" content="ie=edge">
-    <title>test</title>
-</head>
-
-<body>
-    <div>
-        <h1>hello Node.js</h1>
-    </div>
-</body>
-
-</html>

+ 0 - 26
Node.js/test/readFile.js

@@ -1,26 +0,0 @@
-let http = require('http');
-let url = require('url');
-let util = require('util');
-let fs = require('fs');
-
-let server = http.createServer((req, res) => {
-  // 通过浏览器端访问的地址获取文件名
-  var pathname = url.parse(req.url).pathname;
-  fs.readFile(pathname.substring(1), (err, data) => {
-    if (err) {
-      res.writeHead(404, {
-        'Content-Type': 'text/html'
-      });
-    } else {
-      res.writeHead(200, {
-        'Content-Type': 'text/html'
-      });
-      res.write(data.toString());
-    }
-    res.end();
-  });
-});
-
-server.listen(3000, '127.0.0.1', () => {
-  console.log("服务器已经运行,请打开浏览器,输入:http://127.0.0.1:3000/ 来进行访问")
-});

+ 104 - 0
README.md

@@ -0,0 +1,104 @@
+# utils
+
+### Array  
+#### &emsp;&emsp;[arrayEqual][arrayEqual]&emsp;&emsp;判断两个数组是否相等 
+
+### Class
+#### &emsp;&emsp;[addClass][addClass]&emsp;&emsp;为元素添加class  
+#### &emsp;&emsp;[hasClass][hasClass]&emsp;&emsp;判断元素是否有某个class  
+#### &emsp;&emsp;[removeClass][removeClass]&emsp;&emsp;为元素移除class  
+
+### Cookie 
+#### &emsp;&emsp;[getCookie][getCookie]&emsp;&emsp;根据name读取Cookie  
+#### &emsp;&emsp;[removeCookie][removeCookie]&emsp;&emsp;根据name删除Cookie
+#### &emsp;&emsp;[setCookie][setCookie]&emsp;&emsp;添加Cookie 
+
+### Device  
+#### &emsp;&emsp;[getExplore][getExplore]&emsp;&emsp;获取浏览器类型和版本号  
+#### &emsp;&emsp;[getOS][getOS]&emsp;&emsp;获取操作系统类型
+
+### Dom  
+#### &emsp;&emsp;[getScrollTop][getScrollTop]&emsp;&emsp;获取滚动条距顶部的距离
+#### &emsp;&emsp;[offset][offset]&emsp;&emsp;获取一个元素的距离文档(document)的位置,类似jQ中的offset()
+#### &emsp;&emsp;[scrollTo][scrollTo]&emsp;&emsp;在${duration}时间内,滚动条平滑滚动到${to}指定位置
+#### &emsp;&emsp;[setScrollTop][setScrollTop]&emsp;&emsp;设置滚动条距顶部的距离
+
+### Function  
+#### &emsp;&emsp;[debounce][debounce]&emsp;&emsp;函数防抖   
+#### &emsp;&emsp;[throttle][throttle]&emsp;&emsp;函数节流   
+
+### Keycode  
+#### &emsp;&emsp;[getKeyName][getKeyName]&emsp;&emsp;根据keycode获得键名 
+
+### Object  
+#### &emsp;&emsp;[deepClone][deepClone]&emsp;&emsp;深拷贝,支持常见类型
+#### &emsp;&emsp;[isEmptyObject][isEmptyObject]&emsp;&emsp;判断Object是否为空
+
+### Random  
+#### &emsp;&emsp;[randomColor][randomColor] &emsp;&emsp;随机生成颜色
+#### &emsp;&emsp;[randomNum][randomNum]&emsp;&emsp;生成指定范围随机数 
+
+### Regexp  
+#### &emsp;&emsp;[isEmail][isEmail]&emsp;&emsp;判断是否为邮箱地址 
+#### &emsp;&emsp;[isIdCard][isIdCard]&emsp;&emsp;判断是否为身份证号
+#### &emsp;&emsp;[isPhoneNum][isPhoneNum]&emsp;&emsp;判断是否为手机号  
+#### &emsp;&emsp;[isUrl][isUrl]&emsp;&emsp;判断是否为URL地址
+
+### String  
+#### &emsp;&emsp;[digitUppercase][digitUppercase]&emsp;&emsp;现金额转大写
+
+### Support  
+#### &emsp;&emsp;[isSupportWebP][isSupportWebP]&emsp;&emsp;判断浏览器是否支持webP格式图片
+#### 
+
+### Time  
+#### &emsp;&emsp;[formatPassTime][formatPassTime]&emsp;&emsp;格式化${startTime}距现在的已过时间
+#### &emsp;&emsp;[formatRemainTime][formatRemainTime]&emsp;&emsp;格式化现在距${endTime}的剩余时间
+
+### Url
+#### &emsp;&emsp;[parseQueryString][parseQueryString]&emsp;&emsp;url参数转对象
+#### &emsp;&emsp;[stringfyQueryString][stringfyQueryString]&emsp;&emsp;对象序列化
+
+[arrayEqual]:https://github.com/striveDJiang/utils/array/arrayEqual.js
+
+[addClass]:https://github.com/striveDJiang/utils/class/addClass.js
+[hasClass]:https://github.com/striveDJiang/utils/class/hasClass.js
+[removeClass]:https://github.com/striveDJiang/utils/class/removeClass.js
+
+[getCookie]:https://github.com/striveDJiang/utils/cookie/getCookie.js
+[removeCookie]:https://github.com/striveDJiang/utils/cookie/removeCookie.js
+[setCookie]:https://github.com/striveDJiang/utils/cookie/setCookie.js
+
+[getExplore]:https://github.com/striveDJiang/utils/device/getExplore.js
+[getOS]:https://github.com/striveDJiang/utils/device/getOS.js
+
+[getScrollTop]:https://github.com/striveDJiang/utils/dom/getScrollTop.js
+[offset]:https://github.com/striveDJiang/utils/dom/offset.js
+[scrollTo]:https://github.com/striveDJiang/utils/dom/scrollTo.js
+[setScrollTop]:https://github.com/striveDJiang/utils/dom/setScrollTop.js
+
+[debounce]:https://github.com/striveDJiang/utils/function/debounce.js
+[throttle]:https://github.com/striveDJiang/utils/function/throttle.js
+
+[getKeyName]:https://github.com/striveDJiang/utils/keycode/getKeyName.js
+
+[deepClone]:https://github.com/striveDJiang/utils/object/deepClone.js
+[isEmptyObject]:https://github.com/striveDJiang/utils/object/isEmptyObject.js
+
+[randomColor]:https://github.com/striveDJiang/utils/random/randomColor.js
+[randomNum]:https://github.com/striveDJiang/utils/random/randomNum.js
+
+[isEmail]:https://github.com/striveDJiang/utils/regexp/isEmail.js
+[isIdCard]:https://github.com/striveDJiang/utils/regexp/isIdCard.js
+[isPhoneNum]:https://github.com/striveDJiang/utils/regexp/isPhoneNum.js
+[isUrl]:https://github.com/striveDJiang/utils/regexp/isUrl.js
+
+[digitUppercase]:https://github.com/striveDJiang/utils/string/digitUppercase.js
+
+[isSupportWebP]:https://github.com/striveDJiang/utils/support/isSupportWebP.js
+
+[formatPassTime]:https://github.com/striveDJiang/utils/time/formatPassTime.js
+[formatRemainTime]:https://github.com/striveDJiang/utils/time/formatRemainTime.js
+
+[parseQueryString]:https://github.com/striveDJiang/utils/url/parseQueryString.js
+[stringfyQueryString]:https://github.com/striveDJiang/utils/url/stringfyQueryString.js

+ 0 - 109
Vue.js/components/select-dropdown-1.vue

@@ -1,109 +0,0 @@
-<!--下拉选择组件-->
-<template>
-    <div class="selection-component">
-        <div class="selection-show" @click="toggleDrop">
-            <!-- 显示选中的项 -->
-            <span>{{ selections[nowIndex].label }}</span>
-            <div class="arrow"></div>
-        </div>
-        <div class="selection-list" v-if="isDrop">
-            <ul>
-                <!-- 遍历选项数组 -->
-                <li v-for="(item, index) in selections" @click="dropdownSelection(index)">
-                    {{ item.label }}
-                </li>
-            </ul>
-        </div>
-    </div>
-</template>
-
-<script>
-export default {
-    props: {
-        // 接收父级传递过来的选项数据,并定义类型和默认值
-        selections: {
-            type: Array,
-            default: [{
-                label: 'test',
-                value: 0
-            }]
-        }
-    },
-    data() {
-        return {
-            nowIndex: 0,
-            isDrop: false
-        }
-    },
-    methods: {
-        toggleDrop(event) {
-            this.isDrop = !this.isDrop
-        },
-        dropdownSelection(index) {
-            this.nowIndex = index
-            this.isDrop = false
-            // 触发on-chosen事件,向父组件传递选中的项
-            this.$emit('on-chosen', this.selections[this.nowIndex])
-        }
-    }
-}
-</script>
-
-<style scoped>
-.selection-component {
-    position: relative;
-    display: inline-block;
-}
-
-.selection-show {
-    border: 1px solid #e3e3e3;
-    padding: 0 20px 0 10px;
-    display: inline-block;
-    position: relative;
-    cursor: pointer;
-    height: 25px;
-    line-height: 25px;
-    border-radius: 3px;
-    background: #fff;
-}
-
-.selection-show .arrow {
-    display: inline-block;
-    border-left: 4px solid transparent;
-    border-right: 4px solid transparent;
-    border-top: 5px solid #e3e3e3;
-    width: 0;
-    height: 0;
-    margin-top: -1px;
-    margin-left: 6px;
-    margin-right: -14px;
-    vertical-align: middle;
-}
-
-.selection-list {
-    display: inline-block;
-    position: absolute;
-    left: 0;
-    top: 25px;
-    width: 100%;
-    background: #fff;
-    border-top: 1px solid #e3e3e3;
-    border-bottom: 1px solid #e3e3e3;
-    z-index: 5;
-}
-
-.selection-list li {
-    padding: 5px 15px 5px 10px;
-    border-left: 1px solid #e3e3e3;
-    border-right: 1px solid #e3e3e3;
-    cursor: pointer;
-    background: #fff;
-    white-space: nowrap;
-    overflow: hidden;
-    text-overflow: ellipsis;
-}
-
-.selection-list li:hover {
-    background: #e3e3e3;
-}
-</style>

+ 0 - 78
Vue.js/components/select-multiterm-1.vue

@@ -1,78 +0,0 @@
-<!--多选组件-->
-<template>
-    <div class="chooser-component">
-        <ul class="chooser-list">
-            <!-- 遍历选项数组 -->
-            <li v-for="(item, index) in selections" :title="item.label" :class="{active: checkActive(index)}" @click="multiSelect(index)">
-                {{ item.label }}
-            </li>
-        </ul>
-    </div>
-</template>
-
-<script>
-// 引入JavaScript工具库lodash
-import _ from 'lodash'
-export default {
-    props: {
-        // 接收父级传递过来的选项数据,并定义类型和默认值
-        selections: {
-            type: Array,
-            default: [{
-                label: 'test',
-                value: 0
-            }]
-        }
-    },
-    data() {
-        return {
-            nowIndexes: [0]
-        }
-    },
-    methods: {
-        multiSelect(index) {
-            if (this.nowIndexes.indexOf(index) === -1) {
-                this.nowIndexes.push(index)
-            }
-            else {
-                this.nowIndexes = _.remove(this.nowIndexes, (idx) => {
-                    return idx !== index
-                })
-            }
-            let nowObjArray = _.map(this.nowIndexes, (idx) => {
-                return this.selections[idx]
-            })
-            // 触发on-chosen事件,向父组件传递选中的项
-            this.$emit('on-chosen', nowObjArray)
-        },
-        checkActive(index) {
-            return this.nowIndexes.indexOf(index) !== -1
-        }
-    }
-}
-</script>
-
-<style scoped>
-.chooser-component {
-    position: relative;
-    display: inline-block;
-}
-
-.chooser-list li {
-    display: inline-block;
-    border: 1px solid #e3e3e3;
-    height: 25px;
-    line-height: 25px;
-    padding: 0 8px;
-    margin-right: 5px;
-    border-radius: 3px;
-    text-align: center;
-    cursor: pointer;
-}
-
-.chooser-list li.active {
-    border-color: #4fc08d;
-    background: #4fc08d;
-    color: #fff;
-}
-</style>

+ 0 - 108
Vue.js/components/select-number-1.vue

@@ -1,108 +0,0 @@
-<!--数字选择组件-->
-<template>
-    <div class="counter-component">
-        <div class="counter-btn" @click="minus"> - </div>
-        <div class="counter-show">
-            <input type="text" v-model="number" @keyup="fixNumber">
-        </div>
-        <div class="counter-btn" @click="add"> + </div>
-    </div>
-</template>
-
-<script>
-export default {
-    props: {
-        // 接收父级传递过来的最大值,并定义类型和默认值
-        max: {
-            type: Number,
-            default: 5
-        },
-        // 接收父级传递过来的最小值,并定义类型和默认值
-        min: {
-            type: Number,
-            default: 1
-        }
-    },
-    data() {
-        return {
-            number: this.min
-        }
-    },
-    watch: {
-        number() {
-            // 触发on-number事件,向父组件传递数值
-            this.$emit('on-number', this.number)
-        }
-    },
-    methods: {
-        fixNumber() {
-            let fix
-            if (typeof this.number === 'string') {
-                fix = Number(this.number.replace(/\D/g, ''))
-            }
-            else {
-                fix = this.number
-            }
-            if (fix > this.max) {
-                fix = this.max
-            }
-            else if (fix < this.min) {
-                fix = this.min
-            }
-            this.number = fix
-        },
-        minus() {
-            if (this.number <= this.min) {
-                return
-            }
-            this.number--
-        },
-        add() {
-            if (this.number >= this.max) {
-                return
-            }
-            this.number++
-        }
-    }
-}
-</script>
-
-<style scoped>
-.counter-component {
-    position: relative;
-    display: inline-block;
-    overflow: hidden;
-    vertical-align: middle;
-}
-
-.counter-show {
-    float: left;
-}
-
-.counter-show input {
-    border: none;
-    border-top: 1px solid #e3e3e3;
-    border-bottom: 1px solid #e3e3e3;
-    height: 23px;
-    line-height: 23px;
-    width: 30px;
-    outline: none;
-    text-indent: 4px;
-}
-
-.counter-btn {
-    border: 1px solid #e3e3e3;
-    float: left;
-    height: 25px;
-    line-height: 25px;
-    width: 25px;
-    text-align: center;
-    cursor: pointer;
-}
-
-.counter-btn:hover {
-    border-color: #4fc08d;
-    background: #4fc08d;
-    color: #fff;
-}
-</style>

+ 0 - 63
Vue.js/components/select-single-1.vue

@@ -1,63 +0,0 @@
-<!--单选组件-->
-<template>
-    <div class="chooser-component">
-        <ul class="chooser-list">
-            <!-- 遍历选项数组 -->
-            <li v-for="(item, index) in selections" :title="item.label" :class="{active:index === nowIndex}" @click="singleSelection(index)">
-                {{ item.label }}
-            </li>
-        </ul>
-    </div>
-</template>
-
-<script>
-export default {
-    props: {
-        // 接收父级传递过来的选项数据,并定义类型和默认值
-        selections: {
-            type: Array,
-            default: [{
-                label: 'test',
-                value: 0
-            }]
-        }
-    },
-    data() {
-        return {
-            nowIndex: 0
-        }
-    },
-    methods: {
-        singleSelection(index) {
-            this.nowIndex = index
-            // 触发on-chosen事件,向父组件传递选中的项
-            this.$emit('on-chosen', this.selections[index])
-        }
-    }
-}
-</script>
-
-<style scoped>
-.chooser-component {
-    position: relative;
-    display: inline-block;
-}
-
-.chooser-list li {
-    display: inline-block;
-    border: 1px solid #e3e3e3;
-    height: 25px;
-    line-height: 25px;
-    padding: 0 8px;
-    margin-right: 5px;
-    border-radius: 3px;
-    text-align: center;
-    cursor: pointer;
-}
-
-.chooser-list li.active {
-    border-color: #4fc08d;
-    background: #4fc08d;
-    color: #fff;
-}
-</style>

+ 0 - 154
Vue.js/components/slideShow-1.vue

@@ -1,154 +0,0 @@
-<!--幻灯片组件-->
-<template>
-    <div class="slide-show" @mouseover="clearInv" @mouseout="runInv">
-        <div class="slide-img">
-            <a href="javascript:;">
-                <transition name="slide-trans">
-                    <!-- 轮播图 -->
-                    <img v-if="isShow" :src="slides[nowIndex].src">
-                </transition>
-                <transition name="slide-trans-old">
-                    <img v-if="!isShow" :src="slides[nowIndex].src">
-                </transition>
-            </a>
-        </div>
-        <h2>{{ slides[nowIndex].title }}</h2>
-        <ul class="slide-pages">
-            <li @click="goto(prevIndex)">&lt;</li>
-            <!-- 遍历幻灯片数组 -->
-            <li v-for="(item, index) in slides" @click="goto(index)">
-                <a :class="{on: index === nowIndex}">
-                    {{ index + 1 }}
-                </a>
-            </li>
-            <li @click="goto(nextIndex)">&gt;</li>
-        </ul>
-    </div>
-</template>
-
-<script>
-export default {
-    props: {
-        // 接收父级传递过来的幻灯片数据,并定义类型和默认值
-        slides: {
-            type: Array,
-            default: []
-        },
-        // 接收父级传递过来的幻灯片自动轮播的时间,并定义类型和默认值
-        inv: {
-            type: Number,
-            default: 1000
-        }
-    },
-    data() {
-        return {
-            nowIndex: 0,
-            isShow: true
-        }
-    },
-    computed: {
-        prevIndex() {
-            if (this.nowIndex === 0) {
-                return this.slides.length - 1
-            }
-            else {
-                return this.nowIndex - 1
-            }
-        },
-        nextIndex() {
-            if (this.nowIndex === this.slides.length - 1) {
-                return 0
-            }
-            else {
-                return this.nowIndex + 1
-            }
-        }
-    },
-    methods: {
-        goto(index) {
-            this.isShow = false
-            setTimeout(() => {
-                this.isShow = true
-                this.nowIndex = index
-            }, 10)
-        },
-        runInv() {
-            this.invId = setInterval(() => {
-                this.goto(this.nextIndex)
-            }, this.inv)
-        },
-        clearInv() {
-            clearInterval(this.invId)
-        }
-    },
-    mounted() {
-        this.runInv();
-    }
-}
-</script>
-
-<style scoped>
-.slide-trans-enter-active {
-    transition: all .5s;
-}
-
-.slide-trans-enter {
-    transform: translateX(900px);
-}
-
-.slide-trans-old-leave-active {
-    transition: all .5s;
-    transform: translateX(-900px);
-}
-
-.slide-show {
-    position: relative;
-    margin: 15px 15px 15px 0;
-    width: 900px;
-    height: 400px;
-    overflow: hidden;
-}
-
-.slide-show h2 {
-    position: absolute;
-    width: 100%;
-    height: 100%;
-    color: #fff;
-    background: #000;
-    opacity: .5;
-    bottom: 0;
-    height: 30px;
-    line-height: 30px;
-    text-align: left;
-    padding-left: 15px;
-}
-
-.slide-img {
-    width: 100%;
-}
-
-.slide-img img {
-    width: 100%;
-    position: absolute;
-    top: 0;
-}
-
-.slide-pages {
-    position: absolute;
-    bottom: 10px;
-    right: 15px;
-}
-
-.slide-pages li {
-    display: inline-block;
-    padding: 0 10px;
-    cursor: pointer;
-    color: #fff;
-}
-
-.slide-pages li .on {
-    border-radius: 50%;
-    background-color: #6f6265;
-    padding: 0 5px;
-}
-</style>

+ 17 - 0
array/arrayEqual.js

@@ -0,0 +1,17 @@
+/**
+ * 
+ * @desc 判断两个数组是否相等
+ * @param {Array} arr1 
+ * @param {Array} arr2 
+ * @return {Boolean}
+ */
+function arrayEqual(arr1, arr2) {
+    if (arr1 === arr2) return true;
+    if (arr1.length != arr2.length) return false;
+    for (var i = 0; i < arr1.length; ++i) {
+        if (arr1[i] !== arr2[i]) return false;
+    }
+    return true;
+}
+
+module.exports = arrayEqual;

+ 17 - 0
class/addClass.js

@@ -0,0 +1,17 @@
+/**
+ * 
+ * @desc   为元素添加class
+ * @param  {HTMLElement} ele 
+ * @param  {String} cls 
+ */
+
+var hasClass = require('./hasClass');
+
+function addClass(ele, cls) {
+    if (!hasClass(ele, cls)) {
+        ele.className += ' ' + cls;
+    }
+}
+
+
+module.exports = addClass;

+ 12 - 0
class/hasClass.js

@@ -0,0 +1,12 @@
+/**
+ * 
+ * @desc 判断元素是否有某个class
+ * @param {HTMLElement} ele 
+ * @param {String} cls 
+ * @return {Boolean}
+ */
+function hasClass(ele, cls) {
+    return (new RegExp('(\\s|^)' + cls + '(\\s|$)')).test(ele.className);
+}
+
+module.exports = hasClass;

+ 16 - 0
class/removeClass.js

@@ -0,0 +1,16 @@
+/**
+ * 
+ * @desc 为元素移除class
+ * @param {HTMLElement} ele 
+ * @param {String} cls 
+ */
+
+var hasClass = require('./hasClass');
+
+function removeClass(ele, cls) {
+    if (hasClass(ele, cls)) {
+        var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
+        ele.className = ele.className.replace(reg, ' ');
+    }
+}
+module.exports = removeClass;

+ 18 - 0
cookie/getCookie.js

@@ -0,0 +1,18 @@
+/**
+ * 
+ * @desc 根据name读取cookie
+ * @param  {String} name 
+ * @return {String}
+ */
+function getCookie(name) {
+    var arr = document.cookie.replace(/\s/g, "").split(';');
+    for (var i = 0; i < arr.length; i++) {
+        var tempArr = arr[i].split('=');
+        if (tempArr[0] == name) {
+            return decodeURIComponent(tempArr[1]);
+        }
+    }
+    return '';
+}
+
+module.exports = getCookie

+ 12 - 0
cookie/removeCookie.js

@@ -0,0 +1,12 @@
+var setCookie = require('./setCookie');
+/**
+ * 
+ * @desc 根据name删除cookie
+ * @param  {String} name 
+ */
+function removeCookie(name) {
+    // 设置已过期,系统会立刻删除cookie
+    setCookie(name, '1', -1);
+}
+
+module.exports = removeCookie

+ 14 - 0
cookie/setCookie.js

@@ -0,0 +1,14 @@
+/**
+ * 
+ * @desc  设置Cookie
+ * @param {String} name 
+ * @param {String} value 
+ * @param {Number} days 
+ */
+function setCookie(name, value, days) {
+    var date = new Date();
+    date.setDate(date.getDate() + days);
+    document.cookie = name + '=' + value + ';expires=' + date;
+}
+
+module.exports = setCookie

+ 27 - 0
device/getExplore.js

@@ -0,0 +1,27 @@
+/**
+ * 
+ * @desc 获取浏览器类型和版本
+ * @return {String} 
+ */
+function getExplore() {
+    var sys = {},
+        ua = navigator.userAgent.toLowerCase(),
+        s;
+    (s = ua.match(/rv:([\d.]+)\) like gecko/)) ? sys.ie = s[1]:
+        (s = ua.match(/msie ([\d\.]+)/)) ? sys.ie = s[1] :
+        (s = ua.match(/edge\/([\d\.]+)/)) ? sys.edge = s[1] :
+        (s = ua.match(/firefox\/([\d\.]+)/)) ? sys.firefox = s[1] :
+        (s = ua.match(/(?:opera|opr).([\d\.]+)/)) ? sys.opera = s[1] :
+        (s = ua.match(/chrome\/([\d\.]+)/)) ? sys.chrome = s[1] :
+        (s = ua.match(/version\/([\d\.]+).*safari/)) ? sys.safari = s[1] : 0;
+    // 根据关系进行判断
+    if (sys.ie) return ('IE: ' + sys.ie)
+    if (sys.edge) return ('EDGE: ' + sys.edge)
+    if (sys.firefox) return ('Firefox: ' + sys.firefox)
+    if (sys.chrome) return ('Chrome: ' + sys.chrome)
+    if (sys.opera) return ('Opera: ' + sys.opera)
+    if (sys.safari) return ('Safari: ' + sys.safari)
+    return 'Unkonwn'
+}
+
+module.exports = getExplore;

+ 19 - 0
device/getOS.js

@@ -0,0 +1,19 @@
+/**
+ * 
+ * @desc 获取操作系统类型
+ * @return {String} 
+ */
+function getOS() {
+    var userAgent = 'navigator' in window && 'userAgent' in navigator && navigator.userAgent.toLowerCase() || '';
+    var vendor = 'navigator' in window && 'vendor' in navigator && navigator.vendor.toLowerCase() || '';
+    var appVersion = 'navigator' in window && 'appVersion' in navigator && navigator.appVersion.toLowerCase() || '';
+
+    if (/mac/i.test(appVersion)) return 'MacOSX'
+    if (/win/i.test(appVersion)) return 'windows'
+    if (/linux/i.test(appVersion)) return 'linux'
+    if (/iphone/i.test(userAgent) || /ipad/i.test(userAgent) || /ipod/i.test(userAgent)) 'ios'
+    if (/android/i.test(userAgent)) return 'android'
+    if (/win/i.test(appVersion) && /phone/i.test(userAgent)) return 'windowsPhone'
+}
+
+module.exports = getOS;

+ 9 - 0
dom/getScrollTop.js

@@ -0,0 +1,9 @@
+/**
+ * 
+ * @desc 获取滚动条距顶部的距离
+ */
+function getScrollTop() {
+    return (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;
+}
+
+module.exports = getScrollTop;

+ 20 - 0
dom/offset.js

@@ -0,0 +1,20 @@
+/**
+ * 
+ * @desc  获取一个元素的距离文档(document)的位置,类似jQ中的offset()
+ * @param {HTMLElement} ele 
+ * @returns { {left: number, top: number} }
+ */
+function offset(ele) {
+    var pos = {
+        left: 0,
+        top: 0
+    };
+    while (ele) {
+        pos.left += ele.offsetLeft;
+        pos.top += ele.offsetTop;
+        ele = ele.offsetParent;
+    };
+    return pos;
+}
+
+module.exports = offset;

+ 39 - 0
dom/scrollTo.js

@@ -0,0 +1,39 @@
+var getScrollTop = require('./getScrollTop');
+var setScrollTop = require('./setScrollTop');
+var requestAnimFrame = (function () {
+    return window.requestAnimationFrame ||
+        window.webkitRequestAnimationFrame ||
+        window.mozRequestAnimationFrame ||
+        function (callback) {
+            window.setTimeout(callback, 1000 / 60);
+        };
+})();
+/**
+ * 
+ * @desc  在${duration}时间内,滚动条平滑滚动到${to}指定位置
+ * @param {Number} to 
+ * @param {Number} duration 
+ */
+function scrollTo(to, duration) {
+    if (duration < 0) {
+        setScrollTop(to);
+        return
+    }
+    var diff = to - getScrollTop();
+    if (diff === 0) return
+    var step = diff / duration * 10;
+    requestAnimationFrame(
+        function () {
+            if (Math.abs(step) > Math.abs(diff)) {
+                setScrollTop(getScrollTop() + diff);
+                return;
+            }
+            setScrollTop(getScrollTop() + step);
+            if (diff > 0 && getScrollTop() >= to || diff < 0 && getScrollTop() <= to) {
+                return;
+            }
+            scrollTo(to, duration - 16);
+        });
+}
+
+module.exports = scrollTo;

+ 10 - 0
dom/setScrollTop.js

@@ -0,0 +1,10 @@
+/**
+ * 
+ * @desc 设置滚动条距顶部的距离
+ */
+function setScrollTop(value) {
+    window.scrollTo(0, value);
+    return value;
+}
+
+module.exports = setScrollTop;

+ 20 - 0
function/debounce.js

@@ -0,0 +1,20 @@
+var throttle = require('./throttle');
+
+/**
+ * @desc 函数防抖 
+ * 与throttle不同的是,debounce保证一个函数在多少毫秒内不再被触发,只会执行一次,
+ * 要么在第一次调用return的防抖函数时执行,要么在延迟指定毫秒后调用。
+ * @example 适用场景:如在线编辑的自动存储防抖。
+ * @param  {Number}   delay         0或者更大的毫秒数。 对于事件回调,大约100或250毫秒(或更高)的延迟是最有用的。
+ * @param  {Boolean}  atBegin       可选,默认为false。
+ *                                  如果`atBegin`为false或未传入,回调函数则在第一次调用return的防抖函数后延迟指定毫秒调用。
+                                    如果`atBegin`为true,回调函数则在第一次调用return的防抖函数时直接执行
+ * @param  {Function} callback      延迟毫秒后执行的函数。`this`上下文和所有参数都是按原样传递的,
+ *                                  执行去抖动功能时,,调用`callback`。
+ *
+ * @return {Function} 新的防抖函数。
+ */
+function debounce(delay, atBegin, callback) {
+    return callback === undefined ? throttle(delay, atBegin, false) : throttle(delay, callback, atBegin !== false);
+};
+module.exports = debounce;

+ 89 - 0
function/throttle.js

@@ -0,0 +1,89 @@
+/**
+ * @desc   函数节流。
+ * 适用于限制`resize`和`scroll`等函数的调用频率
+ *
+ * @param  {Number}    delay          0 或者更大的毫秒数。 对于事件回调,大约100或250毫秒(或更高)的延迟是最有用的。
+ * @param  {Boolean}   noTrailing     可选,默认为false。
+ *                                    如果noTrailing为true,当节流函数被调用,每过`delay`毫秒`callback`也将执行一次。
+ *                                    如果noTrailing为false或者未传入,`callback`将在最后一次调用节流函数后再执行一次.
+ *                                    (延迟`delay`毫秒之后,节流函数没有被调用,内部计数器会复位)
+ * @param  {Function}  callback       延迟毫秒后执行的函数。`this`上下文和所有参数都是按原样传递的,
+ *                                    执行去节流功能时,调用`callback`。
+ * @param  {Boolean}   debounceMode   如果`debounceMode`为true,`clear`在`delay`ms后执行。
+ *                                    如果debounceMode是false,`callback`在`delay` ms之后执行。
+ *
+ * @return {Function}  新的节流函数
+ */
+module.exports = function throttle(delay, noTrailing, callback, debounceMode) {
+
+    // After wrapper has stopped being called, this timeout ensures that
+    // `callback` is executed at the proper times in `throttle` and `end`
+    // debounce modes.
+    var timeoutID;
+
+    // Keep track of the last time `callback` was executed.
+    var lastExec = 0;
+
+    // `noTrailing` defaults to falsy.
+    if (typeof noTrailing !== 'boolean') {
+        debounceMode = callback;
+        callback = noTrailing;
+        noTrailing = undefined;
+    }
+
+    // The `wrapper` function encapsulates all of the throttling / debouncing
+    // functionality and when executed will limit the rate at which `callback`
+    // is executed.
+    function wrapper() {
+
+        var self = this;
+        var elapsed = Number(new Date()) - lastExec;
+        var args = arguments;
+
+        // Execute `callback` and update the `lastExec` timestamp.
+        function exec() {
+            lastExec = Number(new Date());
+            callback.apply(self, args);
+        }
+
+        // If `debounceMode` is true (at begin) this is used to clear the flag
+        // to allow future `callback` executions.
+        function clear() {
+            timeoutID = undefined;
+        }
+
+        if (debounceMode && !timeoutID) {
+            // Since `wrapper` is being called for the first time and
+            // `debounceMode` is true (at begin), execute `callback`.
+            exec();
+        }
+
+        // Clear any existing timeout.
+        if (timeoutID) {
+            clearTimeout(timeoutID);
+        }
+
+        if (debounceMode === undefined && elapsed > delay) {
+            // In throttle mode, if `delay` time has been exceeded, execute
+            // `callback`.
+            exec();
+
+        } else if (noTrailing !== true) {
+            // In trailing throttle mode, since `delay` time has not been
+            // exceeded, schedule `callback` to execute `delay` ms after most
+            // recent execution.
+            //
+            // If `debounceMode` is true (at begin), schedule `clear` to execute
+            // after `delay` ms.
+            //
+            // If `debounceMode` is false (at end), schedule `callback` to
+            // execute after `delay` ms.
+            timeoutID = setTimeout(debounceMode ? clear : exec, debounceMode === undefined ? delay - elapsed : delay);
+        }
+
+    }
+
+    // Return the wrapper function.
+    return wrapper;
+
+};

+ 124 - 0
keycode/getKeyName.js

@@ -0,0 +1,124 @@
+var keyCodeMap = {
+    8: 'Backspace',
+    9: 'Tab',
+    13: 'Enter',
+    16: 'Shift',
+    17: 'Ctrl',
+    18: 'Alt',
+    19: 'Pause',
+    20: 'Caps Lock',
+    27: 'Escape',
+    32: 'Space',
+    33: 'Page Up',
+    34: 'Page Down',
+    35: 'End',
+    36: 'Home',
+    37: 'Left',
+    38: 'Up',
+    39: 'Right',
+    40: 'Down',
+    42: 'Print Screen',
+    45: 'Insert',
+    46: 'Delete',
+
+    48: '0',
+    49: '1',
+    50: '2',
+    51: '3',
+    52: '4',
+    53: '5',
+    54: '6',
+    55: '7',
+    56: '8',
+    57: '9',
+
+    65: 'A',
+    66: 'B',
+    67: 'C',
+    68: 'D',
+    69: 'E',
+    70: 'F',
+    71: 'G',
+    72: 'H',
+    73: 'I',
+    74: 'J',
+    75: 'K',
+    76: 'L',
+    77: 'M',
+    78: 'N',
+    79: 'O',
+    80: 'P',
+    81: 'Q',
+    82: 'R',
+    83: 'S',
+    84: 'T',
+    85: 'U',
+    86: 'V',
+    87: 'W',
+    88: 'X',
+    89: 'Y',
+    90: 'Z',
+
+    91: 'Windows',
+    93: 'Right Click',
+
+    96: 'Numpad 0',
+    97: 'Numpad 1',
+    98: 'Numpad 2',
+    99: 'Numpad 3',
+    100: 'Numpad 4',
+    101: 'Numpad 5',
+    102: 'Numpad 6',
+    103: 'Numpad 7',
+    104: 'Numpad 8',
+    105: 'Numpad 9',
+    106: 'Numpad *',
+    107: 'Numpad +',
+    109: 'Numpad -',
+    110: 'Numpad .',
+    111: 'Numpad /',
+
+    112: 'F1',
+    113: 'F2',
+    114: 'F3',
+    115: 'F4',
+    116: 'F5',
+    117: 'F6',
+    118: 'F7',
+    119: 'F8',
+    120: 'F9',
+    121: 'F10',
+    122: 'F11',
+    123: 'F12',
+
+    144: 'Num Lock',
+    145: 'Scroll Lock',
+    182: 'My Computer',
+    183: 'My Calculator',
+    186: ';',
+    187: '=',
+    188: ',',
+    189: '-',
+    190: '.',
+    191: '/',
+    192: '`',
+    219: '[',
+    220: '\\',
+    221: ']',
+    222: '\''
+};
+/**
+ * @desc 根据keycode获得键名
+ * @param  {Number} keycode 
+ * @return {String}
+ */
+function getKeyName(keycode) {
+    if (keyCodeMap[keycode]) {
+        return keyCodeMap[keycode];
+    } else {
+        console.log('Unknow Key(Key Code:' + keycode + ')');
+        return '';
+    }
+};
+
+module.exports = getKeyName;

+ 39 - 0
object/deepClone.js

@@ -0,0 +1,39 @@
+/**
+ * @desc 深拷贝,支持常见类型
+ * @param {Any} values
+ */
+function deepClone(values) {
+    var copy;
+
+    // Handle the 3 simple types, and null or undefined
+    if (null == values || "object" != typeof values) return values;
+
+    // Handle Date
+    if (values instanceof Date) {
+        copy = new Date();
+        copy.setTime(values.getTime());
+        return copy;
+    }
+
+    // Handle Array
+    if (values instanceof Array) {
+        copy = [];
+        for (var i = 0, len = values.length; i < len; i++) {
+            copy[i] = deepClone(values[i]);
+        }
+        return copy;
+    }
+
+    // Handle Object
+    if (values instanceof Object) {
+        copy = {};
+        for (var attr in values) {
+            if (values.hasOwnProperty(attr)) copy[attr] = deepClone(values[attr]);
+        }
+        return copy;
+    }
+
+    throw new Error("Unable to copy values! Its type isn't supported.");
+}
+
+module.exports = deepClone

+ 13 - 0
object/isEmptyObject.js

@@ -0,0 +1,13 @@
+/**
+ * 
+ * @desc   判断`obj`是否为空
+ * @param  {Object} obj
+ * @return {Boolean}
+ */
+function isEmptyObject(obj) {
+    if (!obj || typeof obj !== 'object' || Array.isArray(obj))
+        return false
+    return !Object.keys(obj).length
+}
+
+module.exports = isEmptyObject

+ 10 - 0
random/randomColor.js

@@ -0,0 +1,10 @@
+/**
+ * 
+ * @desc 随机生成颜色
+ * @return {String} 
+ */
+function randomColor() {
+    return '#' + ('00000' + (Math.random() * 0x1000000 << 0).toString(16)).slice(-6);
+}
+
+module.exports = randomColor;

+ 12 - 0
random/randomNum.js

@@ -0,0 +1,12 @@
+/**
+ * 
+ * @desc 生成指定范围随机数
+ * @param  {Number} min 
+ * @param  {Number} max 
+ * @return {Number} 
+ */
+function randomNum(min, max) {
+    return Math.floor(min + Math.random() * (max - min));
+}
+
+module.exports = randomNum;

+ 11 - 0
regexp/isEmail.js

@@ -0,0 +1,11 @@
+/**
+ * 
+ * @desc   判断是否为邮箱地址
+ * @param  {String}  str
+ * @return {Boolean} 
+ */
+function isEmail(str) {
+    return /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(str);
+}
+
+module.exports = isEmail;

+ 11 - 0
regexp/isIdCard.js

@@ -0,0 +1,11 @@
+/**
+ * 
+ * @desc  判断是否为身份证号
+ * @param  {String|Number} str 
+ * @return {Boolean}
+ */
+function isIdCard(str) {
+    return /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/.test(str)
+}
+
+module.exports = isIdCard

+ 11 - 0
regexp/isPhoneNum.js

@@ -0,0 +1,11 @@
+/**
+ * 
+ * @desc   判断是否为手机号
+ * @param  {String|Number} str 
+ * @return {Boolean} 
+ */
+function isPhoneNum(str) {
+    return /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/.test(str)
+}
+
+module.exports = isPhoneNum

+ 11 - 0
regexp/isUrl.js

@@ -0,0 +1,11 @@
+/**
+ * 
+ * @desc   判断是否为URL地址
+ * @param  {String} str 
+ * @return {Boolean}
+ */
+function isUrl(str) {
+    return /[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/i.test(str);
+}
+
+module.exports = isUrl;

+ 38 - 0
string/digitUppercase.js

@@ -0,0 +1,38 @@
+/**
+ * 
+ * @desc   现金额转大写
+ * @param  {Number} n 
+ * @return {String}
+ */
+function digitUppercase(n) {
+    var fraction = ['角', '分'];
+    var digit = [
+        '零', '壹', '贰', '叁', '肆',
+        '伍', '陆', '柒', '捌', '玖'
+    ];
+    var unit = [
+        ['元', '万', '亿'],
+        ['', '拾', '佰', '仟']
+    ];
+    var head = n < 0 ? '欠' : '';
+    n = Math.abs(n);
+    var s = '';
+    for (var i = 0; i < fraction.length; i++) {
+        s += (digit[Math.floor(n * 10 * Math.pow(10, i)) % 10] + fraction[i]).replace(/零./, '');
+    }
+    s = s || '整';
+    n = Math.floor(n);
+    for (var i = 0; i < unit[0].length && n > 0; i++) {
+        var p = '';
+        for (var j = 0; j < unit[1].length && n > 0; j++) {
+            p = digit[n % 10] + unit[1][j] + p;
+            n = Math.floor(n / 10);
+        }
+        s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s;
+    }
+    return head + s.replace(/(零.)*零元/, '元')
+        .replace(/(零.)+/g, '零')
+        .replace(/^整$/, '零元整');
+};
+
+module.exports = digitUppercase

+ 10 - 0
support/isSupportWebP.js

@@ -0,0 +1,10 @@
+/**
+ * 
+ * @desc 判断浏览器是否支持webP格式图片
+ * @return {Boolean} 
+ */
+function isSupportWebP() {
+    return !![].map && document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0;
+}
+
+module.exports = isSupportWebP;

+ 22 - 0
time/formatPassTime.js

@@ -0,0 +1,22 @@
+/**
+ * @desc   格式化${startTime}距现在的已过时间
+ * @param  {Date} startTime 
+ * @return {String}
+ */
+function formatPassTime(startTime) {
+    var currentTime = Date.parse(new Date()),
+        time = currentTime - startTime,
+        day = parseInt(time / (1000 * 60 * 60 * 24)),
+        hour = parseInt(time / (1000 * 60 * 60)),
+        min = parseInt(time / (1000 * 60)),
+        month = parseInt(day / 30),
+        year = parseInt(month / 12);
+    if (year) return year + "年前"
+    if (month) return month + "个月前"
+    if (day) return day + "天前"
+    if (hour) return hour + "小时前"
+    if (min) return min + "分钟前"
+    else return '刚刚'
+}
+
+module.exports = formatPassTime

+ 24 - 0
time/formatRemainTime.js

@@ -0,0 +1,24 @@
+/**
+ * 
+ * @desc   格式化现在距${endTime}的剩余时间
+ * @param  {Date} endTime  
+ * @return {String}
+ */
+function formatRemainTime(endTime) {
+    var startDate = new Date(); //开始时间
+    var endDate = new Date(endTime); //结束时间
+    var t = endDate.getTime() - startDate.getTime(); //时间差
+    var d = 0,
+        h = 0,
+        m = 0,
+        s = 0;
+    if (t >= 0) {
+        d = Math.floor(t / 1000 / 3600 / 24);
+        h = Math.floor(t / 1000 / 60 / 60 % 24);
+        m = Math.floor(t / 1000 / 60 % 60);
+        s = Math.floor(t / 1000 % 60);
+    }
+    return d + "天 " + h + "小时 " + m + "分钟 " + s + "秒";
+}
+
+module.exports = formatRemainTime

+ 16 - 0
url/parseQueryString.js

@@ -0,0 +1,16 @@
+/**
+ * 
+ * @desc   url参数转对象
+ * @param  {String} url  default: window.location.href
+ * @return {Object} 
+ */
+function parseQueryString(url) {
+    url = url == null ? window.location.href : url
+    var search = url.substring(url.lastIndexOf('?') + 1)
+    if (!search) {
+        return {}
+    }
+    return JSON.parse('{"' + decodeURIComponent(search).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}')
+}
+
+module.exports = parseQueryString

+ 27 - 0
url/stringfyQueryString.js

@@ -0,0 +1,27 @@
+/**
+ * 
+ * @desc   对象序列化
+ * @param  {Object} obj 
+ * @return {String}
+ */
+function stringfyQueryString(obj) {
+    if (!obj) return '';
+    var pairs = [];
+
+    for (var key in obj) {
+        var value = obj[key];
+
+        if (value instanceof Array) {
+            for (var i = 0; i < value.length; ++i) {
+                pairs.push(encodeURIComponent(key + '[' + i + ']') + '=' + encodeURIComponent(value[i]));
+            }
+            continue;
+        }
+
+        pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]));
+    }
+
+    return pairs.join('&');
+}
+
+module.exports = stringfyQueryString