独书先生 Menu

微信小程序如何关闭云开发

需求

新建项目一不小心就会把云开发打开,给开发者带来一些麻烦。接下来,小编结合自己的开发经验,给大家说说如何关闭微信小程序开发工具中的云开发功能。

解决步骤

  1. 首先打开云开发控制台
    打开云开发控制台

  2. 进入控制台后,选择“设置”
    设置

  3. 在设置里点击环境名称,再点击“管理我的环境”
    管理我的环境

  4. 会在右侧打开环境管理,点击删除即可
    点击删除

  5. 会有个提示,再次跟你确认,点击确定
    点击确定

  6. 再用管理员微信扫码确认下就行了,
    管理员微信扫码

  7. 扫完码,在手机上确认,然后就是这样的了
    在手机上确认

总结

以上就是小编在做微信小程序开发过程遇到的如何关闭云开发的经验,如果有不明白的地方吗,欢迎留言交流。

参考

LeetCode刷题笔记:数组中重复的数据

问题

给你一个长度为 n 的整数数组 nums ,其中 nums 的所有整数都在范围 [1, n] 内,且每个整数出现 一次两次 。请你找出所有出现 两次 的整数,并以数组形式返回。

你必须设计并实现一个时间复杂度为 O(n) 且仅使用常量额外空间的算法解决此问题。

示例 1:

输入:nums = [4,3,2,7,8,2,3,1]

输出:[2,3]

示例 2:

输入:nums = [1,1,2]

输出:[1]

示例 3:

输入:nums = [1]

输出:[]

提示:

  • n == nums.length
  • 1 <= n <= 105
  • 1 <= nums[i] <= n
  • nums 中的每个元素出现 一次两次

解法一

思路:

利用 Set 值唯一的特性,不断向一个空的 Set 里面添加 nums 中的数字,再使用 set.add方法,通过获取 set 长度是否增加来判断是否有重复数字出现。

代码:

/**
 * @param {number[]} nums
 * @return {number[]}
 */
var findDuplicates = function(nums) {
    const set = new Set() // 唯一值检验
    const result = [] // 结果数组

    nums.forEach(n => {
        const preSize = set.size

        // 使用 set.add 方法,通过获取 set 长度是否增加来判断是否有重复数字出现
        set.add(n)

        // 发现重复数字
        if(preSize === set.size){
            result.push(n)
        }
    })

    return result
};

解法二

思路:

遍历整个数组,将每一个数字视为数组位置信息,再将每一个位置对应的数字反转为负数,相当于做一个标识,表明这个数字对应的位置,已经有数字占用了,下一次再遇到这个数字如果发现是负数就表明已经出现过。

比如 [4,3,2,7,8,2,3,1],走到第一个 2 的时候,翻转位置为 1 的数字 3-3,走到下一个 2 的时候,就能发现位置为 1 的数字为 -3, 已经被翻转过了,表明数字 2 出现了两次。

代码:

/**
 * @param {number[]} nums
 * @return {number[]}
 */
var findDuplicates = function(nums) {
    let result = [];
    for (let i = 0; i < nums.length; i++) {
        let num = Math.abs(nums[i]);
        if (nums[num - 1] > 0) {
            /**
             把数字翻转为负数的目的是,做一个标识,表明这个数字对应的位置,已经有数字占用了,下一次再遇到这个数字如果发现是负数就表明已经出现过

             比如[4,3,2,7,8,2,3,1]

             走到第一个2的时候,位置为1的数字为3,将3翻转为-3,走到下一个2的时候,翻转3的时候发现已经被翻转过了
             */
            nums[num - 1] *= -1;
        } else {
            result.push(num);
        }
    }
    return result;

};

参考

李佳琪直播间抢到了娇兰金钻粉底液!

背景

小编的媳妇常年关注李佳琪直播间,所以经常会剁手一些护肤品和化妆品,特别是现在比较火爆流行的化妆品,而且越是火爆的东西越难抢。

前几天就抢到了娇兰金钻粉底液,一个大瓶30ml和6个小样每个5ml。快递到手后立马试用了下,说是感觉效果很不错。

媳妇说,她平时化妆品用的不多,这个化妆品一次买的量又比较大,可以用很久。所以想是不是可以把小样出给集美们,让不想一次买那么多的集美们也能方便的试用一下,试用好的话就可以继续去官网买大瓶的,试用感觉不好的话,反正买的不多也不亏。

福利

我们看下官网的价格,750一个30ml的大瓶,价格已经劝退了没有用过的集美了

这个价格折算一个小样5ml的125一个,可见这个粉底液真的很受欢迎。媳妇说这个价值125的小样,打折给关注咱们公众号的朋友100包邮的价格出。

有朋友注意到,小红书和闲鱼上也有很多更便宜的卖这些护肤品的商家,大家一定要注意甄别,不是说价格便宜的一定不好,而是你想想为啥官网125价值的粉底液,为啥卖你半价不到,而且还能卖那么多?关键脸蛋是自己的,现在网上的假货实在太多了,大家一定要注意。

有意向的小伙伴,关注公众号:技术分社,后台回复:小编,即可添加微信咨询。

微信openHacking

总结

因为这个粉底液实在太抢手了,估计能很快出完。出完了也没有关系,之后抢到了其他好用的护肤品或者化妆品,我们还会考虑出一些给需要的小伙伴。

你可以先关注微信公众号或者直接添加文章底部的微信,有新的东西,我们再第一时间更新公众号和朋友圈。
谢谢大家的支持。

js toFixed精度问题兼容方法

原生的js的toFixed有精确度问题,需要兼容.

问题:

1.35.toFixed(1) // 1.4 正确
1.335.toFixed(2) // 1.33 错误
1.3335.toFixed(3) // 1.333 错误
1.33335.toFixed(4) // 1.3334 正确
1.333335.toFixed(5) // 1.33333 错误
1.3333335.toFixed(6) // 1.333333 错误

解决方法:

// toFixed兼容方法
Number.prototype.toFixed = function (n) {
    if (n > 20 || n < 0) {
        throw new RangeError('toFixed() digits argument must be between 0 and 20');
    }
    const number = this;
    if (isNaN(number) || number >= Math.pow(10, 21)) {
        return number.toString();
    }
    if (typeof (n) == 'undefined' || n == 0) {
        return (Math.round(number)).toString();
    }

    let result = number.toString();
    const arr = result.split('.');

    // 整数的情况
    if (arr.length < 2) {
        result += '.';
        for (let i = 0; i < n; i += 1) {
            result += '0';
        }
        return result;
    }

    const integer = arr[0];
    const decimal = arr[1];
    if (decimal.length == n) {
        return result;
    }
    if (decimal.length < n) {
        for (let i = 0; i < n - decimal.length; i += 1) {
            result += '0';
        }
        return result;
    }
    result = integer + '.' + decimal.substr(0, n);
    const last = decimal.substr(n, 1);

    // 四舍五入,转换为整数再处理,避免浮点数精度的损失
    if (parseInt(last, 10) >= 5) {
        const x = Math.pow(10, n);
        result = (Math.round((parseFloat(result) * x)) + 1) / x;
        result = result.toFixed(n);
    }

    return result;
};

参考自:https://www.jianshu.com/p/849b0ae36b36

Tree树形控件展示当前路径

问题

现有一个树形结构的菜单,支持无限的嵌套层级,需要根据用户点击的某个子菜单,获取到这个子菜单所在节点的路径,类似于面包屑效果。

一个合格的树形菜单数据结构

const menu = [{
          id:'1',
          label: '一级 1',
          children: [{
            id:'11',
            label: '二级 1-1',
            children: [{
              id:'111',
              label: '三级 1-1-1'
            }]
          }]
        }, {
          id:'2',
          label: '一级 2',
          children: [{
            id:'21',
            label: '二级 2-1',
            children: [{
              id:'211',
              label: '三级 2-1-1'
            }]
          }, {
            id:'22',
            label: '二级 2-2',
            children: [{
              id:'221',
              label: '三级 2-2-1'
            }]
          }]
        }, {
          id:'3',
          label: '一级 3',
          children: [{
            id:'31',
            label: '二级 3-1',
            children: [{
              id:'311',
              label: '三级 3-1-1'
            }]
          }, {
            id:'32',
            label: '二级 3-2',
            children: [{
              id:'321',
              label: '三级 3-2-1'
            }]
          }]
        }]

解决方案

思路:

递归整个树形菜单,记录下每次循环时候的当前路径名称,匹配到之后再把所有节点名称拼接起来。

其中有一个关键处理点是每次循环到同级数组,需要重新开始记录路径,否则会出现路径重复的情况

代码:

/**
 * @param {array[][]} data 整个菜单数组
 * @param {object[][]} v 当前节点对象
 * @return {string[]} 当前节点对象路径
 */

function findPath(data, v){
            var find = false; //找到id后标记,结束递归
            var paths = [];

            findId(data, v.id);

            return paths.join('/');

            function findId(root, vid) {

                var currentPathsLength = paths.length;

                root.forEach((ele, i, root) => {
                    // 后面不再循环找了
                    if (find) {
                        return
                    }

                    // 每次循环到同级数组,重新开始记录路径
                    paths = paths.slice(0,currentPathsLength);
                    paths.push(ele.label)


                    // 找到即返回
                    if (ele.id === vid) {
                        find = true;
                        return;
                    } else if (Array.isArray(ele.children) && ele.children.length > 0) { //有子节点继续寻找
                        return findId(ele.children, vid)
                    }

                });

            }
        }

在线演示:

See the Pen
zYKeVJe
by alex (@dushusir)
on CodePen.

js倒计时自定义小时分钟

需求

实现一个倒计时一小时的网页应用

代码







Document

小时
分钟
<p class="count"></p>

<button id="start">START</button>
<script>
  window.onload = function () {
    // countDown();

    document.querySelector("#start").addEventListener("click", () => {
      function addZero(i) {
        return i < 10 ? "0" + i : i + "";
      }

      var hour = document.querySelector("#hour");
      var min = document.querySelector("#min");
      var countTimeHour = parseInt(hour.value === "" ? "1" : hour.value);
      var countTimeMin = parseInt(min.value === "" ? "0" : min.value);

      var nowtime = new Date(); //你已知的时间
      var t_s = nowtime.getTime(); //转化为时间戳毫秒数
      var endtime = new Date(); //定义一个新时间
      t_s = t_s + 1000 * 60 * countTimeMin; //设置新时间比旧时间多一分钟
      t_s = t_s + 1000 * 60 * 60 * countTimeHour; //设置新时间比旧时间多一小时;
      endtime.setTime(t_s);
      // nt.setTime(t_s+1000*60*60*24);//设置新时间比旧时间多一天

      countDown();

      function countDown() {
        var nowtime = new Date(); //你已知的时间
        //   var endtime = new Date("2019/03/16,17:57:00");
        var lefttime = parseInt(
          (endtime.getTime() - nowtime.getTime()) / 1000
        );
        var d = parseInt(lefttime / (24 * 60 * 60));
        var h = parseInt((lefttime / (60 * 60)) % 24);
        var m = parseInt((lefttime / 60) % 60);
        var s = parseInt(lefttime % 60);
        d = addZero(d);
        h = addZero(h);
        m = addZero(m);
        s = addZero(s);
        document.querySelector(
          ".count"
        ).innerHTML = `活动倒计时  ${d}天 ${h} 时 ${m} 分 ${s} 秒`;
        if (lefttime <= 0) {
          document.querySelector(".count").innerHTML = "Time Over!";
          var isShow = false;
          setInterval(() => {
            isShow = !isShow;
            if (isShow) {
              document.title = "😆Time Over!";
            } else {
              document.title = "";
            }
          }, 1000);
          return;
        }
        setTimeout(countDown, 1000);
      }
    });
    // window.countDown = function () {

    // };
  };
</script>



jquery error Uncaught TypeError: ((x.event.special[i.origType] || (intermediate value)).handle || i.handler).apply is not a function

问题

jquery error:

Uncaught TypeError: ((x.event.special[i.origType] || (intermediate value)).handle || i.handler).apply is not a function

思路

可能的问题来源

按照网上的方法一一排查
1. 事件监听的函数没有具体内容

// Not Working
$('#btnClick').click(function(){   //code })
  1. 调用的方法不存在
var foo = {
bar1: function(){
    alert('working');
}
};


// Not Working because bar2 doesn't exist
$('body').on('click', '.my-button', foo.bar2);

// Working
$('body').on('click', '.my-button', foo.bar1);

  1. 手误绑定了两次
// Not Working
$(document).on('change', '#selectInput').on('change', '#selectInput', function () {});

// Working
$(document).off('change', '#selectInput').on('change', '#selectInput', function () {});

  1. 监听写法错误
// Not Working
$('body').click('click','.delete_item',function(e){})

// Working
$('body').on('click','.delete_item',function(e){}) 

  1. 监听事件handler不是function
// Not Working
$('.foo').click($('.bar').trigger('click'));

// Working
$('.foo').click(function () {
  $('.bar').trigger('click');
});
  1. 监听的元素不存在
// Not Working if '.js-test' didn't exist anymore.
$(document).on('click', '.js-test', App.test);

一般情况下,监听写的不多,或者已知最近改了哪几个地方,是可以查出来的。但是如果元素特别多,一眼看不出来的情况,就需要使用点调试手段。

如何调试出问题点?

步骤:
1. 格式化format jquery
2. 找到报错的地方,在后面打印event的console,参考如下打印方法:

((p.event.special[r.origType] || {}).handle || r.handler).apply(o.elem, l) || console.log(t)
  1. 复现bug,在报错出现后,找到报错之前的console日志,点开event找到handleObj.handler,一般情况下这个handler是一个function,你可以看看其他正常的情况,但是在这里,这可能是一个对象或者字符串,所以在这之后绑定的apply会报错,这时候就能根据这里的信息,去代码里搜索定位了。

比如我的错误是这样的,我在这个位置的handler是

{
    guid: 12
    preventScroll: true
}

是一个对象,随机搜索’preventScroll’发现了一段代码

$("#" + selector).attr("tabindex", 0).focus({
    preventScroll: true 
});

但是focus里面是支持这种写法的,所以删除tabindex即可

$("#" + selector).focus({      
    preventScroll: true 
});

参考

https://stackoverflow.com/questions/32231036/uncaught-typeerror-x-event-speciali-origtype-intermediate-value-handl

诗歌诗句垂直排版css

需求:

上一篇小编写了首打油诗 暴风雨 ,很多小伙伴咨询如何排版的,其实很简单运用了一个css属性 writing-mode,这个属性在国际化中经常用到,因为有的海外国家的阅读和书写习惯跟我们不一样,嗯,跟我们古文的排版有点像,也算是巧合了,有了这个属性可以运用.

Continue reading…

js实现指定时间倒计时,带标题闪烁提示

问题

  1. 经常需要设定一个活动倒计时提醒,指定一个时间进行倒计时
  2. 或者是自己做时间规划,做计时功能指定到几点完成任务,这时候还需要在网页标签上有提醒

解决

主要是时间的计算

代码如下

<!DOCTYPE html>
<html lang="en">

<head>
      
    <meta charset="UTF-8">
      <title>倒计时</title>
      <style>
        * {
            margin: 0;
            padding: 0;
        }

        div,p {
            font-size: 80px;
            text-align: center;
        }

        #showTime span {
            color: red;
        }

        #showTime span.time {
            color: black
        }

        body {
            padding-top: 200px;
        }
    </style>
</head>

<body>
    <div>距离 <div id="timeSpan"></div> 还有</div>
    <p id="showTime"><span></span></p>
    <script>
        var timeSet = '2020/4/13 00:10:00';
        document.querySelector('#timeSpan').innerHTML = timeSet;
        var msg = {
            time: 0,
            title: document.title,
            timer: null,
            //显示新消息提示
            show: function () {
                var title = msg.title.replace("", "").replace("【时间到啦】", "");
                //定时器,此处产生闪烁
                //由于定时器无法清除,在此调用之前先主动清除一下定时器打到缓冲效果,否则定时器效果叠加标题闪烁频率越来越快
                clearTimeout(msg.timer);
                msg.timer = setTimeout(function () {
                    msg.time++;
                    msg.show();
                    if (msg.time % 2 == 0) {
                        document.title = "【时间到啦】" + title
                    } else {
                        document.title = title
                    };
                }, 300);
                return [msg.timer, msg.title];
            },
            //取消新消息提示
            //此处起名最好不要用clear,由于关键字问题有时可能会无效
            clears: function () {
                clearTimeout(msg.timer);
                document.title = "哈哈哈";
            }
        };
        var oSpan = document.getElementsByTagName('span')[0];
        function tow(n) {
            return n >= 0 && n < 10 ? '0' + n : '' + n;
        }
        function getDate() {
            var oDate = new Date();//获取日期对象
            var oldTime = oDate.getTime();//现在距离1970年的毫秒数
            var newDate = new Date(timeSet);
            var newTime = newDate.getTime();//2019年距离1970年的毫秒数
            var second = Math.floor((newTime - oldTime) / 1000);//未来时间距离现在的秒数
            var day = Math.floor(second / 86400);//整数部分代表的是天;一天有24*60*60=86400秒 ;
            second = second % 86400;//余数代表剩下的秒数;
            var hour = Math.floor(second / 3600);//整数部分代表小时;
            second %= 3600; //余数代表 剩下的秒数;
            var minute = Math.floor(second / 60);
            second %= 60;
            var str =
                tow(day) + '<span class="time">天</span>'
                + tow(hour) + '<span class="time">小时</span>'
                + tow(minute) + '<span class="time">分钟</span>'
                + tow(second) + '<span class="time">秒</span>';
            oSpan.innerHTML = str;
            if (tow(minute) == '00' && tow(second) == '00') {
                msg.show()
                alert('时间到啦!')
            }
        }
        getDate();
        setInterval(getDate, 1000);
    </script>
</body>

</html>

网页内拖动iframe避坑方法

问题:

网页内拖动一个元素比较简单,但是如果是一个iframe,那么鼠标进入iframe内部后会失焦,因为是进入了另一个网页.失焦的结果就是拖动起来一闪一闪的.

解决:

这里采用了一个巧妙的遮罩来避免鼠标进入iframe内失焦问题,iframe用div包裹,iframe同级建一个空白div,初始时宽高为0,一旦mousedown则把宽高置为100%沾满父级的div遮住同级的iframe,这样鼠标拖动的时候就不会触发到iframe内部了, mouseup时再把div置为0,保持iframe内的正常监听.

代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>drag</title>
    <style>
        *{
            padding: 0;
            margin: 0;
        }
        body{
            background-color: #929292;
        }
        .move {
            position: absolute;
            /*设置绝对定位,脱离文档流,便于拖拽*/
            display: block;
            width: 320px;
            height: 486px;
            background-color: transparent;
            cursor: move;
            /*鼠标呈拖拽状*/
            border:10px solid transparent;
        }
        iframe{
            position: absolute;
            width: 100%;
            height: 100%;
        }
        .mask{
            position: absolute;
            cursor: move;
            user-select: none;
        }
    </style>
</head>

<body>
    <div id="drag" class="move">
        <iframe  src="https://m.baidu.com" frameborder="no" border="0" marginwidth="0" marginheight="0" scrolling="no" allowtransparency="yes">可拖动区域</iframe>
        <div class="mask"></div>
    </div>

    <script>
        // 拖拽功能(主要是触发三个事件:onmousedown\onmousemove\onmouseup)
        var drag = document.getElementById('drag');
        var divMask = document.querySelector('.mask');

        // 点击某物体时,用drag对象即可,move和up是全局区域,也就是整个文档通用,应该使用document对象而不是drag对象(否则,采用drag对象时物体只能往右方或下方移动)
        drag.onmousedown = function (e) {
            var e = e || window.event // 兼容ie浏览器
            var diffX = e.clientX - drag.offsetLeft // 鼠标点击物体那一刻相对于物体左侧边框的距离=点击时的位置相对于浏览器最左边的距离-物体左边框相对于浏览器最左边的距离
            var diffY = e.clientY - drag.offsetTop

            /* 低版本ie bug:物体被拖出浏览器可是窗口外部时,还会出现滚动条,
                    解决方法是采用ie浏览器独有的2个方法setCapture()\releaseCapture(),这两个方法,
                    可以让鼠标滑动到浏览器外部也可以捕获到事件,而我们的bug就是当鼠标移出浏览器的时候,
                    限制超过的功能就失效了。用这个方法,即可解决这个问题。注:这两个方法用于onmousedown和onmouseup中 */
            if (typeof drag.setCapture !== 'undefined') {
                drag.setCapture()
            }

            divMask.style.width = '100%';
            divMask.style.height = '100%';
            document.onmousemove = function (e) {
                var e = e || window.event // 兼容ie浏览器
                var left = e.clientX - diffX
                var top = e.clientY - diffY

                // 控制拖拽物体的范围只能在浏览器视窗内,不允许出现滚动条
                if (left < 0) {
                    left = 0
                } else if (left > window.innerWidth - drag.offsetWidth) {
                    left = window.innerWidth - drag.offsetWidth
                }
                if (top < 0) {
                    top = 0
                } else if (top > window.innerHeight - drag.offsetHeight) {
                    top = window.innerHeight - drag.offsetHeight
                }

                // 移动时重新得到物体的距离,解决拖动时出现晃动的现象
                drag.style.left = left + 'px'
                drag.style.top = top + 'px'
            }
            document.onmouseup = function (e) { // 当鼠标弹起来的时候不再移动
                console.log('this', this)
                this.onmousemove = null
                this.onmouseup = null // 预防鼠标弹起来后还会循环(即预防鼠标放上去的时候还会移动)

                // 修复低版本ie bug
                if (typeof drag.releaseCapture !== 'undefined') {
                    drag.releaseCapture()
                }

                divMask.style.width = '0';
                divMask.style.height = '0';
            }
        }
    </script>
</body>

</html>

网页内拖动iframe避坑方法