zoukankan      html  css  js  c++  java
  • app接入网易严选:webview注入js的几个坑

    消费贷款app“一刻千金”接入网易严选总结

    主要任务列表

    1. 隐藏相关元素
    2. 商品列表页跳转事件绑定
    3. 获取商品信息(skuid比较复杂)

    隐藏元素

    这部分没什么好讲的,使用原生js的document的api定位元素或者jQuery的选择器定位元素,然后隐藏(hide)或者移除(remove)

    阻止列表页的事件

    搜索到结果后,点击其中某个商品,希望跳转至改造过的详情页(改变了购买方式)。
    搜索列表页的html主要结构如下:

    <ul class="list">
    	<li class="item">
    		<a class="good" data-reactid="aaaaaa">商品1</a>
    	</li>
    	<li class="item">
    		<a class="good" data-reactid="bbbbbb">商品1</a>
    	</li>
    	<li class="item">
    		<a class="good" data-reactid="cccccc">商品1</a>
    	</li>
    </ul>
    

    以往接入京东、苏宁时,列表页商品跳转都是通过<a>标签设置href的,重新绑定事件,并使用preventDefault,可以防止href的跳转;
    严选使用了react技术栈,这里有两个问题:

    1. 没有使用href,跳转是通过绑定事件,而这个事件处理方法是匿名函数,不知道怎么去移除(使用了jquery的off和unbind,都不起作用知识有限,暂留问号???);
    2. 列表页下拉时,加载,所以给每个<a>标签绑定事件,貌似不太友好也不太靠谱。

    最后,采用事件委托的方式,只需给<ul>绑定一个点击事件,通过判断所点击当前元素,找出<a>标签所带的商品信息(取出属性data-reactid的值)。使用stopPropagation方法,可以阻断<a>的点击事件执行,完美。同时,也解决了下拉加载的问题。

    使用jQuery:

    $('ul').off('click').on('click', '.item', function(e) {
        e.stopPropagation();
        //e.currentTarget 当前点击的'.item'元素
        var tag_a = $(e.currentTarget).find('a.good');
        var data_reactid = tag_a.attr('data-reactid');
        var product_id = data_reactid.match(/$d+/g)[0].replace('$', '');
        var obj = {
            link: 'http://m.you.163.com/item/detail?id=' + product_id,
            type: '001'
        };
    
        console.log(obj);
        postData(obj);  //postData是与app通信的方法
    });
    

    原生js:

    var ul = document.getElementsByClassName('list');
    if(ul.length > 0) {
        ul.addEventListener('click', function(e){
            e.stopPropagation();
            var path = e.path();//文档流
            var a = path.filter(item => item.tagName == 'A')//寻找到a标签
            var data_reactid = a[0].getAttribute('data-reactid');
            var obj = {
                link: 'http://m.you.163.com/item/detail?id=' + product_id,
                type: '001'
            };
    
            console.log(obj);
            postData(obj);//postData是与app通信的方法
        })
    }
    

    使用事件委托的方式,还有个很大的好处。如果循环给<a>标签绑定点击事件,导致该页面存在大量事件处理程序,会影响性能。
    在测试时,一直有个奇怪的问题:大量情况下,能确定该段js完整注入并执行,但是通过调试,就是观察不到ul的click事件;只有很小的几率成功。
    并且webview注入该js时,确定是在页面渲染完成后才注入的。
    后来猜想问题可能是react-router生命周期导致的,<ul>这一部分其实是在子路由里面,通过锚点形式。所以webview认为的页面渲染完成,可能其实不包括这段hash路由。
    最后尝试将该事件绑定在<body>上,完美解决。

    获取商品信息--skuid

    京东、苏宁的商品id,在url上可以很直观地的出来;
    而网易严选的商品页面,url中的search部分也有类似id的字段。只可惜,此id并不是需要下单商品的skuid。因为同样商品,不同规格(颜色、尺码等)时,skuid是不一样的。
    经过大量不同商品页面的分析(其实也就试了两个)。
    在商品详情页和选择规格的页面,有一个jsonData的全局变量,其中jsonData.skuMap类似下面的形式:
    jsonData

    该商品有两个规格(颜色和尺码需要选择),很容易分析出,该如何确定,寻找skuid了。
    html

    1. 获得所选规格(颜色、尺码)的值keyList;
    2. 将jsonData.skuMap转为[k,v]的列表skuMapList(使用Object.entries);
    3. 根据keyLlist,过滤筛选skuMapList,正常情况下,skuMapList只剩下一条数据。
    function getSkuId() {
        var spec_cons = document.getElementsByClassName('u-format');
        var selObject = []
        for (var i = 0; i < spec_cons.length - 1; i++) {
            var element = spec_cons[i];
            var selected = element.getElementsByClassName('tab-sel')[0];
            if (selected) {
                var str = selected.getAttribute('data-reactid');
                var kv = str.match(/$d+/g);
                var item = {
                    id: kv[0].replace('$', ''),
                    value: kv[1].replace('$', '')
                }
                selObject.push(item);
            }
        }
    
        polyfill();//解决老旧版本兼容性问题
    
        var skuMapList = Object.entries(jsonData.skuMap);
        for (var i = 0; i < selObject.length; i++) {
            skuMapList = skuMapList.filter(function(item){
                return item[0].indexOf(selObject[i].value) >= 0;
            })
        }
    
        var result_id = null;
    
        if(skuMapList.length == 1) {
            result_id = skuMapList[0][1].id;
        }
    
        return result_id;
    }
    

    老旧版本浏览器不支持Object.entries,Object.keys,Array.filter等方法,这里polyfill()就是检测兼容性:
    方法参考 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript

    function polyfill(){
    	if(!Object.keys){
    		Object.prototype.keys = function(){
    			//fun body
    			...
    		}
    	}
    
    	if(!Object.entirs){
    		Object.prototype.keys = function(){
    			//fun body
    			...
    		}
    	}
    
    	if(!Array.filter){
    		Array.prototype.keys = function(){
    			//fun body
    			...
    		}
    	}
    }
    

    最开始的算法中,找到所选规格的之后,通过拼接字符串得到skuMap的关键字。
    如所选颜色color,尺寸size,那么key = color + ';' + size,最后的结果就是jsonData.skuMap[key]。
    通过大量测试,发现有些情况key = size + ';' + color,导致取不到skuid。
    所以改变算法,将skuMap变为列表,循环过滤。

  • 相关阅读:
    18.VUE学习之-v-for操作对象与数值
    17.VUE学习之- v-for指令的使用方法
    16.VUE学习之-v-show的使用与v-if的差异对比
    Ubuntu系统操作
    虚拟机乌班图系统安装 VMware tools 工具
    ubuntu中如何切换普通用户、root用户
    在Ubuntu18.04安装docker之后,以登陆用户身份执行docker pull jenkins,报错:connect: permission denied
    安装VM-TOOLS,解压tar包时提示目录磁盘空间不足
    超详细的VMware安装ubuntu教程
    如何快速下载ubuntu镜像
  • 原文地址:https://www.cnblogs.com/aliyuntao/p/ykqj-you163.html
Copyright © 2011-2022 走看看