hubyo

hubyo 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑

前端

个人动态

hubyo 赞了文章 · 2020-06-08

微信小程序从入坑到放弃之坑八:textarea在苹果手机中的大Bug

首次在这里写点东西,还请各位大佬担待点。

摘要:
昨天的placeholder-class只是希望各位看官注意,而今天的textarea就绝对是一个超级大坑!而且如果看官手中没有苹果手机测试的话,这个可就真的是个坑了!为啥?难道要等到用户向你反馈你们产品有bug???......
上一篇的《微信小程序从入坑到放弃之坑七:input组件的占位符placeholder》,没啥大坑,而这篇的textarea可就不一样了!这绝对是一个超大的Bug!!!

在上一节的设计稿中,详细地址那块儿就是一个textarea组件。如图:图片描述

其他无关的就不说了,我们直接进入正题。

一、textarea在模拟器、安卓和苹果中的效果

为了便于观察textarea组件的尺寸范围,我们给textarea设置一个背景色。如图:O1CN01NfwGzR1rapSOGbEwT_!!759415648.png
(一个带背景色的textarea组件示例代码一个带背景色的textarea组件示例代码)
然后保存后看下模拟器、安卓手机和苹果手机中的效果吧。如图:O1CN01IXRDIX1rapSQ45Kmv_!!759415648.jpg
(textarea在模拟器和安卓及苹果手机上的效果textarea在模拟器和安卓及苹果手机上的效果)

看到区别了吗?如果没有,再来张大图。如图:O1CN01QkmThs1rapSNf2D5s_!!759415648.png
(textarea在苹果手机上距离顶部有空隙textarea在苹果手机上距离顶部有空隙)

二、不就是个padding吗?!

对于有前端基础的看官来说,一眼就知道这是什么原因。是的,按照正常逻辑,这个空隙就是由padding引起的。

2.1、wxml代码

<textarea style="background:#666;padding:0" value="加padding就有用了吗?"></textarea>

代码写完了,我们再用苹果手机看下效果。如图:O1CN01mEovUD1rapSRiJsBG_!!759415648.jpg
(微信小程序里的textarea设置padding为0时在苹果手机中没有生效)
微信小程序里的textarea设置padding为0时在苹果手机中没有生效可以看到,此时这个padding:0在苹果手机上并没有生效!

奇了怪了,难道textarea不支持padding吗?于是,我又将padding的值修改成40px,此时在安卓手机上的效果如下:O1CN0196giFj1rapSQ45Ox3_!!759415648.jpg
(设置padding为40时在安卓手机中有效设置padding为40时在安卓手机中有效)
我们可以看到,此时安卓手机上是有效的,再来看看苹果手机吧,如图:O1CN01rPEHEI1rapSJMeHMM_!!759415648.jpg
(设置padding为40时在苹果手机中也有效)
咦,怎么又有效果了?!

那这个苹果手机到底支持不支持微信小程序里的textarea组件的padding属性呢?要说不支持吧,修改成40时也有效,要说支持吧,改成0又无效!这就有点坑爹了!

三、微信小程序里的textarea确实有bug

为了便于测试,这回我们直接测一组吧。效果如图:O1CN01iHTZNc1rapSQ44b4r_!!759415648.jpg
(测试发现在微信小程序中,苹果手机对padding的值有临界点)

看到了吗?当值小于或等于0时,在苹果手机中压根就没有任何反应!虽然正常的网页中padding的值是不能为负的!但此时连0!important都无能为力!!!

四、此坑有什么影响

可能有些看官还不知道这坑有什么影响,拿我们的设计稿来说。我们写的页面总得与设计稿一致吧!那些现在问题就来了,这个textarea组件在安卓和苹果上的表现都不一样,要想在两种手机上展现效果一样,必须得对苹果单独处理才行!否则,我们在安卓上布局是好的,到了苹果手机上面,就已经错位了!所以,这就是个超级大坑!要不是因为艺灵我用二手的iphone 6s测试,这个bug估计还不知道什么时候才能知道呢!如果是等到用户反馈才知道,这可是件多么坑爹的事情!!!

五、微信小程序中textarea内边距的坑通吃iphone各版本

看官可能会说:“都什么年代了,艺灵你还用个破6s来测试!”

行,为了验证此bug并非只是iphone 6s才有,于是我又召唤了我的小伙伴们。聊天如图:O1CN01KBopfc1rapSQtbLy6_!!759415648.png
(微信小程序中textarea的内边距bug在iphone各版本上都存在)

这回就问你服不服,iphone X,壕不?X都阵亡了!!!

六、如何解决?

搞过微信小程序的看官都知道,在小程序里面不像正常网页那样可以随便写js,在这里一切都要受限制!

微信小程序官方也有对应的文档,文档地址:
developers.weixin.qq.com/miniprogram/dev/api/system/system-info/wx.getSystemInfo.html?search-key=wx.getSystemInfo 。官方的文档向来都这样,要么不给案例,要么就简短的写下。现在的机型那么多,鬼知道怎么判断啊!于是我又在网上搜索后找到了现成的判断小程序是用安卓还是IOS打开的方法,原文地址:blog.csdn.net/niesiyuan000/article/details/80325988。

顺便补充一句,微信官方提供的判断依旧不全面,最新出来的苹果手机还没有完全支持!相关的坑可以在官方社区的问答中找到。坑!坑!坑!坑!坑!坑!坑!

查看原文

赞 4 收藏 1 评论 0

hubyo 收藏了文章 · 2020-03-05

ELK:kibana使用的lucene查询语法

kibana在ELK阵营中用来查询展示数据
elasticsearch构建在Lucene之上,过滤器语法和Lucene相同


kibana官方演示页面

全文搜索

在搜索栏输入login,会返回所有字段值中包含login的文档

使用双引号包起来作为一个短语搜索
"like Gecko"

字段

也可以按页面左侧显示的字段搜索
限定字段全文搜索:field:value
精确搜索:关键字加上双引号 filed:"value"
http.code:404 搜索http状态码为404的文档

字段本身是否存在
_exists_:http:返回结果中需要有http字段
_missing_:http:不能含有http字段

通配符

? 匹配单个字符
* 匹配0到多个字符

kiba?a, el*search

?* 不能用作第一个字符,例如:?text*text

正则

es支持部分正则功能,性能较差
name:/joh?n(ath[oa]n)/

模糊搜索

quikc~ brwn~ foks~
~:在一个单词后面加上~启用模糊搜索,可以搜到一些拼写错误的单词

first~ 这种也能匹配到 frist

还可以设置编辑距离(整数),指定需要多少相似度
cromm~1 会匹配到 from 和 chrome
默认2,越大越接近搜索的原始值,设置为1基本能搜到80%拼写错误的单词

近似搜索

在短语后面加上~,可以搜到被隔开或顺序不同的单词
"where select"~5 表示 select 和 where 中间可以隔着5个单词,可以搜到 select password from users where id=1

范围搜索

数值/时间/IP/字符串 类型的字段可以对某一范围进行查询
length:[100 TO 200]
sip:["172.24.20.110" TO "172.24.20.140"]
date:{"now-6h" TO "now"}
tag:{b TO e} 搜索b到e中间的字符
count:[10 TO *] * 表示一端不限制范围
count:[1 TO 5} [ ] 表示端点数值包含在范围内,{ } 表示端点数值不包含在范围内,可以混合使用,此语句为1到5,包括1,不包括5
可以简化成以下写法:
age:>10
age:<=10
age:(>=10 AND <20)

优先级

quick^2 fox
使用^使一个词语比另一个搜索优先级更高,默认为1,可以为0~1之间的浮点数,来降低优先级

逻辑操作

AND
OR

+:搜索结果中必须包含此项
-:不能含有此项
+apache -jakarta test aaa bbb:结果中必须存在apache,不能有jakarta,剩余部分尽量都匹配到

分组

(jakarta OR apache) AND jakarta

字段分组

title:(+return +"pink panther")
host:(baidu OR qq OR google) AND host:(com OR cn)

转义特殊字符

+ - = && || > < ! ( ) { } [ ] ^ " ~ * ? : \ /
以上字符当作值搜索的时候需要用\转义
\(1\+1\)\=2用来查询(1+1)=2






参考链接
https://www.elastic.co/guide/... (当前为es 5.5版本)
https://lucene.apache.org/cor...
https://lucene.apache.org/cor...
hhttps://kibana.logstash.es/co...

查看原文

hubyo 赞了文章 · 2020-02-20

微信自定义分享功能,微信js-sdk使用总结

需求:vue项目移动端要求用户在公众号中分享出去的链接是图片+文字+标题的形式。而不是默认的

要实现的效果如图所示:

clipboard.png

不设置时,分享的默认效果,如下图所示:

clipboard.png

几个要注意的地方:

  1. wx.config 所有的配置项的数据都是后台返回的
  2. wx.config配置项的参数大小写一定要按照官网文档来,区分大小写,但是获取到的后台返回的字段可以自由定义,这个时候要注意后台返回的数据字段名称是否和官网的一致,在这块有个问题找了半天,结果最后发现wx.config配置项里面后台返回的res.data.noncestr中noncestr为小写,而自己没有细看一直以为也是nonceStr.导致config:fail.
  3. 分享时,请求的url不能带有hash值等,所以要进行截取

具体参考代码如下所示:

` wxShared() {

  let newUrl = window.location.href.split("#")[0]; //    
  let url = newUrl;

  this.$store.dispatch("GetTicketJSAPI", url).then(res => {
    let params = {
      debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来
      appId: "wx3dab174110e5f840", // 必填,企业微信的corpID
      timestamp: res.data.timestamp, // 必填,生成签名的时间戳***************
      nonceStr: res.data.noncestr, // 必填,生成签名的随机串 必填,生成签名的随机串***************
      signature: res.data.signature, // 必填,签名***************
      jsApiList: ["onMenuShareAppMessage", "onMenuShareTimeline"]
    };
    wx.config(params); //通过config接口注入权限验证配置
    wx.ready(function() {
      // config信息验证成功后会执行ready方法
      //通过ready接口处理成功验证
      wx.onMenuShareAppMessage({
        // 分享给朋友
        title: "声动语商学苑", // 分享标题
        desc: "好语商引领自信人生 · “一站式”专业青少儿语商培养教育品牌", // 分享描述
        link: res.data.str, // 分享链接
        imgUrl:
          "http://www.shengdongyushang.com/upload/asserts/sdys_logo1.png", // 分享图标
        type: "", // 分享类型,music、video或link,不填默认为link
        dataUrl: "", // 如果type是music或video,则要提供数据链接,默认为空
        success: function(res) {
          // 用户确认分享后执行的回调函数
        },
        cancel: function() {
          // 用户取消分享后执行的回调函数
        }
      });
      wx.onMenuShareTimeline({
        //分享朋友圈
        title: "声动语商学苑", // 分享标题
        desc: "好语商引领自信人生 · “一站式”专业青少儿语商培养教育品牌",
        link: res.data.str,
        imgUrl:
          "https://qccdata.qichacha.com/AutoImage/052236e320f34be80991ce01fd8cd138.jpg?x-oss-process=image/resize,w_120", // 分享图标
        success: function(res) {
          // 用户确认分享后执行的回调函数
        },
        cancel: function() {
          // 用户取消分享后执行的回调函数
        }
      });
    });
  });
},`

如果对你有所帮助,麻烦点个赞再走吧 ^_^

查看原文

赞 2 收藏 1 评论 0

hubyo 赞了文章 · 2019-11-26

可能这些是你想要的H5软键盘兼容方案

image

前言

最近一段时间在做 H5 聊天项目,踩过其中一大坑:输入框获取焦点,软键盘弹起,要求输入框吸附(或顶)在输入法框上。需求很明确,看似很简单,其实不然。从实验过一些机型上看,发现主要存在以下问题:

  • AndroidIOS 上,获知软键盘弹起和收起状态存在差异,且页面 webview 表现不同。
  • IOS12 上,微信版本 v6.7.4 及以上,输入框获取焦点,键盘弹起,页面(webview)整体往上滚动,当键盘收起后,不回到原位,导致键盘原来所在位置是空白的。
  • IOS 上,使用第三方输入法,高度计算存在偏差,导致在有些输入法弹起,将输入框挡住一部分。
  • 在有些浏览器上使用一些操作技巧,还是存在输入框被输入法遮挡。

下面就上述发现的问题,逐个探索一下解决方案。

获知软键盘弹起和收起状态

获知软键盘的弹起还是收起状态很重要,后面的兼容处理都要以此为前提。然而,H5 并没有直接监听软键盘的原生事件,只能通过软键盘弹起或收起,引发页面其他方面的表现间接监听,曲线救国。并且,在 IOSAndroid 上的表现不尽相同。

IOS 软键盘弹起表现

IOS 上,输入框(inputtextarea 或 富文本)获取焦点,键盘弹起,页面(webview)并没有被压缩,或者说高度(height)没有改变,只是页面(webview)整体往上滚了,且最大滚动高度(scrollTop)为软键盘高度。

Android 软键盘弹起表现

同样,在 Android 上,输入框获取焦点,键盘弹起,但是页面(webview)高度会发生改变,一般来说,高度为可视区高度(原高度减去软键盘高度),除了因为页面内容被撑开可以产生滚动,webview 本身不能滚动。

IOS 软键盘收起表现

触发软键盘上的“收起”按钮键盘或者输入框以外的页面区域时,输入框失去焦点,软键盘收起。

Android 软键盘收起表现

触发输入框以外的区域时,输入框失去焦点,软键盘收起。但是,触发键盘上的收起按钮键盘时,输入框并不会失去焦点,同样软键盘收起。

软键盘弹起,IOS 和 Android 的 webview 不同表现

监听软键盘弹起和收起

综合上面键盘弹起和收起在 IOSAndroid 上的不同表现,我们可以分开进行如下处理来监听软键盘的弹起和收起:

  • IOS 上,监听输入框的 focus 事件来获知软键盘弹起,监听输入框的 blur 事件获知软键盘收起。
  • Android 上,监听 webview 高度会变化,高度变小获知软键盘弹起,否则软键盘收起。
// 判断设备类型
var judgeDeviceType = function () {
  var ua = window.navigator.userAgent.toLocaleLowerCase();
  var isIOS = /iphone|ipad|ipod/.test(ua);
  var isAndroid = /android/.test(ua);

  return {
    isIOS: isIOS,
    isAndroid: isAndroid
  }
}()

// 监听输入框的软键盘弹起和收起事件
function listenKeybord($input) {
  if (judgeDeviceType.isIOS) {
    // IOS 键盘弹起:IOS 和 Android 输入框获取焦点键盘弹起
    $input.addEventListener('focus', function () {
      console.log('IOS 键盘弹起啦!');
      // IOS 键盘弹起后操作
    }, false)

    // IOS 键盘收起:IOS 点击输入框以外区域或点击收起按钮,输入框都会失去焦点,键盘会收起,
    $input.addEventListener('blur', () => {
      console.log('IOS 键盘收起啦!');
      // IOS 键盘收起后操作
    })
  }

  // Andriod 键盘收起:Andriod 键盘弹起或收起页面高度会发生变化,以此为依据获知键盘收起
  if (judgeDeviceType.isAndroid) {
    var originHeight = document.documentElement.clientHeight || document.body.clientHeight;

    window.addEventListener('resize', function () {
      var resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
      if (originHeight < resizeHeight) {
        console.log('Android 键盘收起啦!');
        // Android 键盘收起后操作
      } else {
        console.log('Android 键盘弹起啦!');
        // Android 键盘弹起后操作
      }

      originHeight = resizeHeight;
    }, false)
  }
}

var $inputs = document.querySelectorAll('.input');

for (var i = 0; i < $inputs.length; i++) {
  listenKeybord($inputs[i]);
}

弹起软键盘始终让输入框滚动到可视区

有时我们会做一个输入表单,有很多输入项,输入框获取焦点,弹起软键盘。当输入框位于页面下部位置时,在 IOS 上,会将 webview 整体往上滚一段距离,使得该获取焦点的输入框自动处于可视区,而在 Android 则不会这样,它只会改变页面高度,而不会去滚动到当前焦点元素到可视区。
由于上面已经实现监听 IOSAndroid 键盘弹起和收起,在这里,只需在 Android 键盘弹起后,将焦点元素滚动(scrollIntoView())到可视区。查看效果,可以戳这里

// 获取到焦点元素滚动到可视区
function activeElementScrollIntoView(activeElement, delay) {
  var editable = activeElement.getAttribute('contenteditable')

  // 输入框、textarea或富文本获取焦点后没有将该元素滚动到可视区
  if (activeElement.tagName == 'INPUT' || activeElement.tagName == 'TEXTAREA' || editable === '' || editable) {
    setTimeout(function () {
      activeElement.scrollIntoView();
    }, delay)
  }
}

// ...
// Android 键盘弹起后操作
activeElementScrollIntoView($input, 1000);
// ...

唤起纯数字软键盘

上面的表单输入框有要求输入电话号码,类似这样就要弹出一个数字软键盘了,既然说到了软键盘兼容,在这里就安插一下。比较好的解决方案如下:

<p>请输入手机号</p>
<input type="tel" novalidate="novalidate" pattern="[0-9]*" class="input">
  • type="tel", 是 HTML5 的一个属性,表示输入框类型为电话号码,在 AndroidIOS 上表现差不多,都会有数字键盘,但是也会有字母,略显多余。
  • pattern="[0-9]"pattern 用于验证表单输入的内容,通常 HTML5type 属性,比如 emailtelnumberdata 类、url 等,已经自带了简单的数据格式验证功能了,加上 pattern 后,前端部分的验证更加简单高效了。IOS 中,只有 [0-9]\* 才可以调起九宫格数字键盘,\d 无效,Android 4.4 以下(包括X5内核),两者都调起数字键盘。
  • novalidate="novalidate"novalidate 属性规定当提交表单时不对其进行验证,由于 pattern 校验兼容性不好,可以不让其校验,只让其唤起纯数字键盘,校验工作由 js 去做。

软键盘弹起,IOS 和 Android 的 webview 不同表现

兼容 IOS12 + V6.7.4+

如果你在用 IOS12V6.7.4+版本的微信浏览器打开上面表单输入的 demo ,就会惊奇的发现键盘收起后,原本被滚动顶起的页面并没有回到底部位置,导致原来键盘弹起的位置“空”了。

兼容 codeIOS12/code + codeV6.7.4+/code

其实这是 AppleIOSbug,会出现在所有的 Xcode10 打包的 IOS12 的设备上。微信官方已给出解决方案,只需在软键盘收起后,将页面(webview)滚回到窗口最底部位置(clientHeight位置)。修复后的上面表单输入 demo 可以戳这里

console.log('IOS 键盘收起啦!');
// IOS 键盘收起后操作
// 微信浏览器版本6.7.4+IOS12会出现键盘收起后,视图被顶上去了没有下来
var wechatInfo = window.navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i);
if (!wechatInfo) return;

var wechatVersion = wechatInfo[1];
var version = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/);

if (+wechatVersion.replace(/\./g, '') >= 674 && +version[1] >= 12) {
  setTimeout(function () {
    window.scrollTo(0, Math.max(document.body.clientHeight, document.documentElement.clientHeight));
  })
}

兼容第三方输入法

上面说了那么多,其实已经把 H5 聊天输入框的坑填了一大半了,接下来就先看下聊天输入框的基本HTML结构

<div class="chat__content">
  <div>
    <p>一些聊天内容1</p>
  </div>
  <!-- 省略几千行聊天内容 -->
</div>
<div class="input__content">
  <div class="input" contenteditable="true"></div>
  <button>发送</button>
</div>

样式

/* 省略一些样式 */
.chat__content {
  height: calc(100% - 40px);
  margin-bottom: 40px;
  overflow-y: auto;
  overflow-x: hidden;
}

.input__content {
  display: flex;
  height: 40px;
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  align-items: center;
}
/* 省略一些样式 */

很简单,就是划分内容区和输入区,输入区是绝对定位,按照上面表单输入 demo 的做法,确实大部分 Android 浏览器是没问题的,但是测试在 IOS 上,UC 浏览器配合原生输入法和第三方输入法(比如搜狗输入法),输入框都会被完全挡住;QQ 浏览器或微信浏览器,配合第三方输入法,输入框会被遮住一半;百度浏览器配合第三方输入法输入框也会被完全遮住。查看效果可以用相应浏览器中访问这里

keyboard-chat-input.png

UC 浏览器上,软键盘弹起后,浏览器上面的标题栏高度就有个高度变小延时动态效果,这样导致 webview 往下滚了一点,底部输入框滚到了非可视区。
而对于第三方输入法,猜测本身是由于输入法面板弹起后高度计算有误,导致 webview 初始滚动定位有误。其实这两点都是 webview 滚动不到位造成的。可以让软键盘弹起后,让焦点元素再次滚到可视区,强迫 webview 滚到位。

console.log('Android 键盘弹起啦!');
// Android 键盘弹起后操作
activeElementScrollIntoView($input, 1000);

兼容 Android 小米浏览器的 Hack 方案

Android 的小米浏览器上,应用上面的方案,发现聊天输入框还是被遮挡得严严实实,scrollIntoView() 仍然纹丝不动。所以猜测,其实是滚到底了,软键盘弹起,页面实现高度大于可视区高度,这样只能在软键盘弹起后,强行增加页面高度,使输入框可以显示出来。综合上面兼容第三方输入法,查看效果可以戳这里

// Andriod 键盘收起:Andriod 键盘弹起或收起页面高度会发生变化,以此为依据获知键盘收起
if (judgeDeviceType.isAndroid) {
  var originHeight = document.documentElement.clientHeight || document.body.clientHeight;

  window.addEventListener('resize', function () {
    var resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
    if (originHeight < resizeHeight) {
      console.log('Android 键盘收起啦!');
      // Android 键盘收起后操作
      // 修复小米浏览器下,输入框依旧被输入法遮挡问题
      if (judgeDeviceType.isMiuiBrowser) {
        document.body.style.marginBottom = '0px';
      }
    } else {
      console.log('Android 键盘弹起啦!');
      // Android 键盘弹起后操作
      // 修复小米浏览器下,输入框依旧被输入法遮挡问题
      if (judgeDeviceType.isMiuiBrowser) {
        document.body.style.marginBottom = '40px';
      }
      activeElementScrollIntoView($input, 1000);
    }

    originHeight = resizeHeight;
  }, false)
}

总结

H5 端前路漫漫,坑很多,需要不断尝试。了解软键盘弹起页面在 IOSAndroid 上的表现差异是前提,其次是将焦点元素滚动到可视区,同时要考虑到第三方输入法和某些浏览器上的差别。总结肯定不全面,欢迎大家指正哈,完~

查看原文

赞 374 收藏 296 评论 36

hubyo 赞了文章 · 2019-08-27

ELK:kibana使用的lucene查询语法

kibana在ELK阵营中用来查询展示数据
elasticsearch构建在Lucene之上,过滤器语法和Lucene相同


kibana官方演示页面

全文搜索

在搜索栏输入login,会返回所有字段值中包含login的文档

使用双引号包起来作为一个短语搜索
"like Gecko"

字段

也可以按页面左侧显示的字段搜索
限定字段全文搜索:field:value
精确搜索:关键字加上双引号 filed:"value"
http.code:404 搜索http状态码为404的文档

字段本身是否存在
_exists_:http:返回结果中需要有http字段
_missing_:http:不能含有http字段

通配符

? 匹配单个字符
* 匹配0到多个字符

kiba?a, el*search

?* 不能用作第一个字符,例如:?text*text

正则

es支持部分正则功能,性能较差
name:/joh?n(ath[oa]n)/

模糊搜索

quikc~ brwn~ foks~
~:在一个单词后面加上~启用模糊搜索,可以搜到一些拼写错误的单词

first~ 这种也能匹配到 frist

还可以设置编辑距离(整数),指定需要多少相似度
cromm~1 会匹配到 from 和 chrome
默认2,越大越接近搜索的原始值,设置为1基本能搜到80%拼写错误的单词

近似搜索

在短语后面加上~,可以搜到被隔开或顺序不同的单词
"where select"~5 表示 select 和 where 中间可以隔着5个单词,可以搜到 select password from users where id=1

范围搜索

数值/时间/IP/字符串 类型的字段可以对某一范围进行查询
length:[100 TO 200]
sip:["172.24.20.110" TO "172.24.20.140"]
date:{"now-6h" TO "now"}
tag:{b TO e} 搜索b到e中间的字符
count:[10 TO *] * 表示一端不限制范围
count:[1 TO 5} [ ] 表示端点数值包含在范围内,{ } 表示端点数值不包含在范围内,可以混合使用,此语句为1到5,包括1,不包括5
可以简化成以下写法:
age:>10
age:<=10
age:(>=10 AND <20)

优先级

quick^2 fox
使用^使一个词语比另一个搜索优先级更高,默认为1,可以为0~1之间的浮点数,来降低优先级

逻辑操作

AND
OR

+:搜索结果中必须包含此项
-:不能含有此项
+apache -jakarta test aaa bbb:结果中必须存在apache,不能有jakarta,剩余部分尽量都匹配到

分组

(jakarta OR apache) AND jakarta

字段分组

title:(+return +"pink panther")
host:(baidu OR qq OR google) AND host:(com OR cn)

转义特殊字符

+ - = && || > < ! ( ) { } [ ] ^ " ~ * ? : \ /
以上字符当作值搜索的时候需要用\转义
\(1\+1\)\=2用来查询(1+1)=2






参考链接
https://www.elastic.co/guide/... (当前为es 5.5版本)
https://lucene.apache.org/cor...
https://lucene.apache.org/cor...
hhttps://kibana.logstash.es/co...

查看原文

赞 55 收藏 91 评论 5

hubyo 赞了文章 · 2019-08-27

小程序自定义导航栏适配(完美版)

1、发现问题

小程序页面自定义导航栏功能已经开放有些日子了(还不知道这个功能的可以先>>了解一下),这极大的提升了小程序开发的自由度,相信不少小伙伴已经使用过这个功能,同时也相信不少小伙伴在此功能开发过程中踩过同样的一些坑:

  • 机型多如牛毛:自定义导航栏高度在不同机型始终无法达到视觉上的统一;
  • 调皮的胶囊按钮:导航栏元素(文字,图标等)怎么也对不齐那该死的胶囊按钮;
  • 各种尺寸的全面屏,奇怪的刘海屏,简直要抓狂。

同样的,这些问题也是小灰经历过的。但是小灰相信,办法总比问题多,于是开始了自己的探究:

2、一探究竟

为了搞明白到底该怎么去适配,老规矩,我先翻了一波官方文档,还别说,官方还真有这么一段介绍了相关细节,>>详情点击

169d422007d60196?w=2482&h=492&f=png&s=307793

从图中分析,我们可以得到如下信息:

  • Android跟iOS有差异,表现在顶部到胶囊按钮之间的距离差了6pt
  • 胶囊按钮高度为32pt, iOS和Android一致

这。。。,好像并没有什么L用啊??这仅仅是普通屏幕为参照的,ipx, 安卓全面屏完全没介绍。
沉着冷静,我们接着分析:

  • 胶囊按钮到状态栏下边缘这块距离,好像是固定的?
  • 安卓这个图,好像有点奇怪?导航栏分为 状态栏+标题栏?
  • 如果车两个条件成立,那我们的问题是不是就解决了80%了?

那么我们来论证一下:

第一个问题:胶囊按钮到状态栏下边缘的距离是不是固定的?

很简单,我们写一个状态栏,通过wx.getSystemInfoSync().statusBarHeight设置高度
为了好测量,我们设置状态栏背景色为深色
js代码:

var sysinfo = wx.getSystemInfoSync();
this.setData({ 
     statusBarHeight:sysinfo.statusBarHeight 
})

wxml代码:

<view class="status-bar" style="height:{{statusBarHeight}}px"></view>

wxss代码:

.status-bar{
    background: rgb(141, 71, 71);
 }

效果图(iPhone6):

169d46522c51dde4?w=756&h=188&f=png&s=16261

效果图(iPhoneX):

169d4668092ad319?w=748&h=206&f=png&s=15022

效果图(安卓):
169d475f38427b32?w=718&h=186&f=png&s=15776

是不是有点眉目了?是的,从截图可以看出,iOS是一致的,但是Android好像有所差别。
那究竟距离是多少?我们用神器(微信截图)来量一量:

Android:
169d47c7bc7e6798?w=762&h=666&f=png&s=64794

iOS:
169d47f76e2cbcc8?w=812&h=666&f=png&s=67052

可以看出,iOS胶囊按钮与状态栏之间距离为:6px, Android为8px,并且经过测量,iOS各机型,Android各机型结果一致(由于篇幅原因,就不一一展示截图了,有兴趣的可以自行测量)

第二个问题:导航栏分为 状态栏+标题栏?

通过对第一个问题的论证,很明显能看出来确实是这样的。并且通过第一个问题的测量结果以及官方提供的数据,我们可以对标题栏高度进行计算:
  • 导航栏高度 = 胶囊按钮高度 + 状态栏到胶囊按钮间距 * 2
  • Android导航栏高度 = 32px + 8px * 2 = 48px
  • iOS导航栏高度 = 32px + 6px * 2 = 44px

*注:由于胶囊按钮是原生组件,为表现一直,其单位在个系统都为px,所以我们的自定义导航栏各个高度的单位都必需是px(切记不能用rpx),才能完美适配。

3、解决问题

通过上述分析,相信小伙伴们都能有一个解决问题的思路了,在上代码之前,小灰再给大家画一下重点:

  • 写自定义导航组件的时候,需要将组件结构一分为二:状态栏 + 标题栏
  • 状态栏高度可通过wx.getSystemInfoSync().statusBarHeight获取
  • 标题栏高度:安卓:48px,iOS:44px
  • 单位必需跟胶囊按钮一致,用px

话不多说,上代码(gitHub地址):
js:

Component({   
   properties: {        
    background: {            
        type: String,            
        value: 'rgba(255, 255, 255, 1)'        
    },        
    color: {            
        type: String,            
        value: 'rgba(0, 0, 0, 1)'        
    },        
    titleText: {            
        type: String,            
        value: '导航栏'        
    },        
    titleImg: {            
        type: String,            
        value: ''        
    },        
    backIcon: {            
        type: String,            
        value: ''        
     },        
    homeIcon: {            
        type: String,            
        value: ''        
    },        
    fontSize: {            
        type: Number,            
        value: 16        
    },        
    iconHeight: {            
        type: Number,            
        value: 19       
    },        
    iconWidth: {            
        type:Number,            
        value: 58        
    }    
   },    
attached: function(){        
   var that = this;        
   that.setNavSize();        
   that.setStyle();    
},    
 data: {
    },    
methods: {        
// 通过获取系统信息计算导航栏高度        
setNavSize: function() {            
var that = this                
    , sysinfo = wx.getSystemInfoSync()                
    , statusHeight = sysinfo.statusBarHeight                
    , isiOS = sysinfo.system.indexOf('iOS') > -1                
    , navHeight;            
if (!isiOS) {                
    navHeight = 48;            
   } else {                
    navHeight = 44;            
}            
that.setData({                
    status: statusHeight,                
    navHeight: navHeight            
  })        
},        
setStyle: function() {            
    var that  = this                
    , containerStyle                
    , textStyle                
    , iconStyle;            
    containerStyle = [                
        'background:' + that.data.background                
        ].join(';');            
        textStyle = [                
        'color:' + that.data.color,                
        'font-size:' + that.data.fontSize + 'px'            
        ].join(';');            
        iconStyle = [                
        'width: ' + that.data.iconWidth + 'px',                
        'height: ' + that.data.iconHeight + 'px'            
        ].join(';');            
        that.setData({               
             containerStyle: containerStyle,                
             textStyle: textStyle,                
             iconStyle: iconStyle            
        })        },        
        // 返回事件        
back: function(){            
    wx.navigateBack({                
        delta: 1            
    })            
    this.triggerEvent('back', {back: 1})        
},        
home: function() {            
    this.triggerEvent('home', {});       
 }   
 }})


wxml:

<view class='nav' style='height: {{status + navHeight}}px'>    
    <view class='status' style='height: {{status}}px;{{containerStyle}}'></view>                               <view class='navbar' style='height:{{navHeight}}px;{{containerStyle}}'>        <view class='back-icon' wx:if="{{backIcon}}" bindtap='back'>                    <image data-original='{{backIcon}}'></image>       
         </view>        
    <view class='home-icon' wx:if="{{homeIcon}}" bindtap='home'>            
        <image data-original='{{homeIcon}}'></image>        
    </view>        [链接描述][10]
    <view class='nav-icon' wx:if="{{titleImg}}">            
    <image data-original='{{titleImg}}' style='{{iconStyle}}'></image>       
     </view>
            <view class='nav-title' wx:if="{{titleText && !titleImg}}">
                <text style='{{textStyle}}'>{{titleText}}</text>
            </view>
        </view>
    </view>

wxss:

.navbar{
    position: relative
}
.back-icon, .home-icon{
    width: 28px;
    height: 100%;
    position: absolute;    
    transform: translateY(-50%);    
    top: 50%;    
    display: flex;
    }
.back-icon{    
    left: 16px;
}
.home-icon{    
    left: 44px
}
.back-icon image{    
    width: 28px;    
    height: 28px;    
    margin: auto;
}
.home-icon image{    
    width: 20px;    
    height: 20px;    
    margin: auto;
}
.nav-title, .nav-icon{    
    position: absolute;    
    transform: translate(-50%, -50%);    
    left: 50%;    
    top: 50%;    
    font-size: 0;    
    font-weight: bold;
}

运行效果图:
169d49ab1b497a06?w=748&h=181&f=png&s=19336
文字标题:

169d49deca93da69?w=746&h=132&f=png&s=19980

图片标题:
169d49c23c3c9a66?w=750&h=174&f=png&s=19465

4、总结

经过小灰的一番论证以及实践经验,最终总结出以上最终解决方案,但希望对小伙伴们有所帮助,如果小伙伴们觉得有用,记得给颗star哦 --> 点我,后续还会更新其他组件。

如果大家有更好的方案或者觉得小灰的方案有问题,欢迎大家留言。

查看原文

赞 76 收藏 51 评论 8

hubyo 赞了文章 · 2019-08-27

小程序自定义单页面、全局导航栏

需求

产品说小程序返回到首页不太方便,想添加返回首页按钮,UI说导航栏能不能设置背景图片,因为那样设计挺好看的。

clipboard.png

需求分析并制定方案

这产品和UI都提需求了,咱也不能反驳哈,所以开始调研,分析可行性方案;1、可以添加悬浮按钮。2、自定义导航栏。
添加悬浮按钮,是看起来是比较简单哈,但是感觉不太优雅,会占据页面的空间,体验也不太好。所以想了下第二种方案,自定义导航栏既可以实现产品的需求还可以满足UI的设计美感,在顶部空白处加上返回首页的按钮,这样和返回按钮还对称(最终如图所示,顶部导航栏是个背景图片,分两块组合起来)。

实现方案

一、实现的前提

1、首先查看文档,看文档里关于自定义导航栏是怎么规定的,有哪些限制;还有小程序自定义导航栏全局配置和单页面配置的微信版本和调试库的最低支持版本。

2、在app.json window 增加 navigationStyle:custom ,顶部导航栏就会消失,只保留右上角胶囊状的按钮,如何修改胶囊的颜色呢;胶囊体目前只支持黑色和白色两种颜色 在app.josn window 加上 "navigationBarTextStyle":"white/black"

3、还要考虑加返回按钮和返回首页的按钮,适配不同的机型

先说下两种配置方法:

①全局配置navigationStyle:

  • 调试基础库>=1.9.0
  • 微信客户端>=6.6.0
app.json

{
  "usingComponents": {
    "navigationBar": "/components/navigationBar/navigationBar"
  },
  "window": {
    "navigationStyle": "custom"
  } 
}

②单页面配置navigationStyle

  • 调试基础库>=2.4.3
  • 微信客户端版本>=7.0.0
自定义的页面.json

{
  "window": {
    "navigationStyle": "default"
  } 
}
{
  "navigationStyle": "custom",
  "usingComponents": {
    "navigationBar": "/components/navigationBar/navigationBar"
  }
}
两者的区别就是,全局配置放在app.json文件里,单页面配置放在自定义页面配置文件里。

二、实现的步骤

以下说下几个要点:

1、自定义导航栏文本,是否显示返回,是否显示返回首页,导航栏高度

2、statusBarHeight,用来获取手机状态栏的高度,这个需要在全局app.js中的onLaunch,调用wx.getSystemInfo获取,navigationBarHeight+默认的高度,这个是设定整个导航栏的高度,

3、还有注意的,在写样式距离和大小时建议都用px,因小程序右边的胶囊也是用的px,不是rpx。

4、因为自定义导航栏每个页面都要写,所以把导航栏封装了公共组件,这样只需要在每个页面引入即可。

如下是封装的导航栏组件:

wxml

<view class="navbar" style="{{'height: ' + navigationBarHeight}}">
  <view style="{{'height: ' + statusBarHeight}}"></view>
  <view class='title-container'>
    <view class='capsule' wx:if="{{ back || home }}">
      <view bindtap='back' wx:if="{{back}}">
        <image data-original='/images/back.png'></image>         
      </view>
      <view bindtap='backHome' wx:if="{{home}}">
        <image data-original='/images/home.png'></image>
      </view>
    </view>
    <view class='title'>{{text}}</view>
  </view>
</view>
<view style="{{'height: ' + navigationBarHeight}};background: white;"></view>
这里有个需注意的问题,就是一般会出现自定义导航栏,下拉页面,导航栏也随着会下拉,这种问题是因为设置fixed后页面元素整体上移了navigationBarHeight,所以在此组件里设置一个空白view元素占用最上面的navigationBarHeight这块高度

wxss

.navbar {
  width: 100%;
  background-color: #1797eb;
  position: fixed;
  top: 0;
  left: 0;
  z-index: 999;
}
.title-container {
  height: 40px;
  display: flex;
  align-items: center;
  position: relative;
}
.capsule {
  margin-left: 10px;
  height: 30px;
  background: rgba(255, 255, 255, 0.6);
  border: 1px solid #fff;
  border-radius: 16px;
  display: flex;
  align-items: center;
}
.capsule > view {
  width: 45px;
  height: 60%;
  position: relative;
.capsule > view:nth-child(2) {
  border-left: 1px solid #fff;  
}
.capsule image {
  width: 50%;
  height: 100%;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%,-50%);
}
.title {
  color: white;
  position: absolute;
  top: 6px;
  left: 104px;
  right: 104px;
  height: 30px;
  line-height: 30px;
  font-size: 14px;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

js

const app = getApp()

Component({

  properties: {
    text: {
      type: String,
      value: 'Wechat'
    },
    back: {
      type: Boolean,
      value: false
    },
    home: {
      type: Boolean,
      value: false
    }
  },
  data: {
    statusBarHeight: app.globalData.statusBarHeight + 'px',
    navigationBarHeight: (app.globalData.statusBarHeight + 44) + 'px'
  },

  methods: {
    backHome: function () {
      let pages = getCurrentPages()
      wx.navigateBack({
        delta: pages.length
      })
    },
    back: function () {
      wx.navigateBack({
        delta: 1
      })
    }
  }
})

json

{
  "component": true,
  "usingComponents": {}
}

最终还需要考虑下版本兼容的问题,毕竟还有一些用户,微信版本并没有更新到最新版本。

首先可以在app.js里面获取下当前用户的微信版本,做下版本比较,如果小于这个版本,设置个全局变量,也可以在组件写个方法,在不同的页面打开显示不同的顶部导航栏,或者可以控制是否显示导航栏,这里就不详细说了。

亲自试了下,在低于7.0版本的微信中,如果采用单页面自定义导航栏,会出现两个导航栏,这时候通过判断版本号不要再渲染自定义的导航栏组件了,在页面的配置文件里写上title名,还有相应的背景色,这样就会显示自带的导航栏了。

总结

小程序开发是有些坑的地方,从不支持自定义导航栏,到支持全局自定义导航栏,再到现在的支持单页面配置,可以看出在慢慢完善。还有底部tabbar,可自己选择配置的太少了,虽然也支持自定义,但是发现自定义写的底部导航组件体验并不好,每次打开页面都会重新渲染底部的按钮,如果全部写成在一个页面里的tab切换,虽然按钮每次不用重新加载了,但是业务多肯定不行,写到一个单页面里东西也太多了。 希望微信能够多添加或放开一些功能,让开发者更好的服务于产品,给用户更好的体验。

查看原文

赞 43 收藏 19 评论 6

hubyo 赞了文章 · 2019-05-17

JavaScript是如何工作的:使用 MutationObserver 跟踪 DOM 的变化

这是专门探索 JavaScript 及其所构建的组件的系列文章的第10篇。

想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!

如果你错过了前面的章节,可以在这里找到它们:

  1. JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述!
  2. JavaScript 是如何工作的:深入V8引擎&编写优化代码的5个技巧!
  3. JavaScript 是如何工作的:内存管理+如何处理4个常见的内存泄漏 !
  4. JavaScript 是如何工作的:事件循环和异步编程的崛起+ 5种使用 async/await 更好地编码方式!
  5. JavaScript 是如何工作的:深入探索 websocket 和HTTP/2与SSE +如何选择正确的路径!
  6. JavaScript 是如何工作的:与 WebAssembly比较 及其使用场景 !
  7. JavaScript 是如何工作的:Web Workers的构建块+ 5个使用他们的场景!
  8. JavaScript 是如何工作的:Service Worker 的生命周期及使用场景!
  9. JavaScript 是如何工作的:Web 推送通知的机制!

图片描述

Web 应用程序在客户端变得越来越重,原因很多,例如需要更丰富的 UI 来容纳更复杂的应用程序提供的内容,实时计算等等。复杂性的增加使得在 Web 应用程序生命周期的每个给定时刻都很难知道 UI 的确切状态。

而当你在搭建某些框架或者库的时候,甚至会更加困难,例如,前者需要根据 DOM 来作出反应并执行特定的动作。

概述

Mutation Observer API 用来监视 DOM 变动。DOM 的任何变动,比如节点的增减、属性的变动、文本内容的变动,这个 API 都可以得到通知。

概念上,它很接近事件,可以理解为 DOM 发生变动就会触发 Mutation Observer 事件。但是,它与事件有一个本质不同:事件是同步触发,也就是说,DOM 的变动立刻会触发相应的事件;Mutation Observer 则是异步触发,DOM 的变动并不会马上触发,而是要等到当前所有 DOM 操作都结束才触发。

这样设计是为了应付 DOM 变动频繁的特点。举例来说,如果文档中连续插入1000个 <li>元素,就会连续触发1000个插入事件,执行每个事件的回调函数,这很可能造成浏览器的卡顿;而 Mutation Observer 完全不同,只在 1000 个段落都插入结束后才会触发,而且只触发一次。

Mutation Observer有以下特点:

  • 它等待所有脚本任务完成后,才会运行,即采用异步方式
  • 它把 DOM 变动记录封装成一个数组进行处理,而不是一条条地个别处理 DOM 变动
  • 它即可以观察发生在 DOM 节点的所有变动,也可以观察某一类变动

为什么要要监听 DOM?

在很多情况下,MutationObserver API 都可以派上用场。例如:

  • 你希望通知 Web 应用程序访问者,他当前所在的页面发生了一些更改。
  • 你正在开发一个新的 JavaScript 框架,需要根据 DOM 的变化动态加载 JavaScript 模块。
  • 也许你正在开发一个所见即所得(WYSIWYG) 编辑器,试图实现撤消/重做功能。通过利用 MutationObserver API,你可以知道在任何给定的点上进行了哪些更改,因此可以轻松地撤消这些更改。

图片描述

这些只是 MutationObserver 可以提供帮助的几个例子。

MutationObserver 用法

在应用程序中实现 MutationObserver 相当简单。你需要通过传入一个函数来创建一个 MutationObserver 实例,每当有变化发生,这个函数将会被调用。函数的第一个参数是变动数组,每个变化都会提供它的类型和已经发生的变化的信息。

var mutationObserver = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    console.log(mutation);
  });
});

这个被创建的对象有三个方法:

  • observe  — 启动监听
  • disconnect — 用来停止观察
  • takeRecords — 返用来清除变动记录,即不再处理未处理的变动。

observe()

observe 方法用来启动监听,它接受两个参数。

  1. 第一个参数:所要观察的 DOM 节点
  2. 第二个参数:一个配置对象,指定所要观察的特定变

下面的片段展示了如何开始启动监听(observe  ):

// 开始侦听页面的根 HTML 元素中的更改。
mutationObserver.observe(document.documentElement, {
  attributes: true,
  characterData: true,
  childList: true,
  subtree: true,
  attributeOldValue: true,
  characterDataOldValue: true
});

现在,假设 DOM 中有一些非常简单的 div:

<div id="sample-div" class="test"> Simple div </div>

使用 JQuery 来移除这个 div 上的 class:

$("#sample-div").removeAttr("class");

正如我们已经开始观察到的,在调用 mutationObserver.observe(…) 之后,将在控制台中看到相应 MutationRecord 的日志:

图片描述

这个是由移除 class 属性导致的变化。

MutationRecord 对象包含了DOM的相关信息,有如下属性:

type:观察的变动类型(attribute、characterData或者childList)
target:发生变动的 DOM 节点
addedNodes:新增的 DOM 节点
removedNodes:删除的 DOM 节点
previousSibling:前一个同级节点,如果没有则返回 null
nextSibling:下一个同级节点,如果没有则返回 null
attributeName:发生变动的属性。如果设置了attributeFilter,则只返回预先指定的属性。
oldValue:变动前的值。这个属性只对 attribute 和 characterData 变动有效,如果发生 childList 变动,则返回 null

最后,为了在任务完成后停止观察 DOM,可以执行以下操作:

mutationObserver.disconnect();

现在,MutationObserver 已经被广泛支持:

图片描述

备择方案

MutationObserver 在之前还没有的,那么在 MutationObserver 还没出现之前,开发者采用什么方案呢?

这是几个可用的其他选项:

  • 轮询(Polling)
  • MutationEvents
  • CSS animations

轮询(Polling)

最简单和最简单的方法是轮询。使用浏览器 setInterval 方法,可以设置一个任务,定期检查是否发生了任何更改。当然,这种方法会显著降低web 应用程序/网站的性能。

MutationEvents

在2000年,MutationEvents API 被引入。虽然很有用,但在 DOM中 的每一次更改都会触发改变事件,这同样会导致性能问题。现在 MutationEvents API 已经被弃用,很快现代浏览器将完全停止支持它。

图片描述

CSS animations

另一个有点奇怪的选择是依赖 CSS 动画。这听起来可能有点令人困惑。基本上,我们的想法是创建一个动画,一旦元素被添加到 DOM 中,动画就会被触发。动画开始的那一刻,animationstart 事件将被触发:如果已经将事件处理程序附加到该事件,那么你将确切地知道元素何时被添加到 DOM 中。动画的执行时间周期应该很小,用户几乎看不到它。

首先,需要一个父级元素,我们在它的内部监听节点的插入:

<div id=”container-element”></div>

为了得到节点插入的处理器,需要设置一系列的 keyframe 动画,当节点插入的时候,动画将会开始。

@keyframes nodeInserted { 
 from { opacity: 0.99; }
 to { opacity: 1; } 
}

创建 keyfram 后,还需要把它放入你想监听的元素上,注意应设置很小的 duration 值 —— 它们将会减弱动画在浏览器上留下的痕迹。

#container-element * {
  animation-duration: 0.001s;
  animation-name: nodeInserted;
}

这会将动画添加到 container-element 的所有子节点。 动画结束时,将触发插入事件。

我们需要一个 JavaScript 函数作为事件监听器。在函数中,必须进行初始的 event.animationName 检查以确保它是我们想要的动画。

var insertionListener = function(event) {
  // Making sure that this is the animation we want.
  if (event.animationName === "nodeInserted") {
    console.log("Node has been inserted: " + event.target);
  }
}

现在是时候为父级元素添加事件监听了:

document.addEventListener(“animationstart”, insertionListener, false); // standard + firefox
document.addEventListener(“MSAnimationStart”, insertionListener, false); // IE
document.addEventListener(“webkitAnimationStart”, insertionListener, false); // Chrome + Safari

浏览器对CSS动画的支持情况:

图片描述

MutationObserver 比上述解决方案有许多优点。本质上,它涵盖了 DOM 中可能发生的每一个更改,并且在批量触发更改时,它的优化程度更高。最重要的是,所有主要的现代浏览器都支持 MutationObserver,还有一些使用引擎下 MutationEvents 的 polyfill。

原文:

https://blog.sessionstack.com...

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

你的点赞是我持续分享好东西的动力,欢迎点赞!

欢迎加入前端大家庭,里面会经常分享一些技术资源。

clipboard.png

查看原文

赞 43 收藏 29 评论 2

hubyo 收藏了问题 · 2019-04-23

微信小程序怎么获取当前页面的url啊

微信小程序怎么获取当前页面的url啊

hubyo 赞了问题 · 2019-04-23

微信小程序怎么获取当前页面的url啊

微信小程序怎么获取当前页面的url啊

关注 10 回答 8

认证与成就

  • 获得 8 次点赞
  • 获得 28 枚徽章 获得 1 枚金徽章, 获得 9 枚银徽章, 获得 18 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2016-03-05
个人主页被 488 人浏览