分类 前端 下的文章

layui的数据表格用起来的确很方便,开发时能节省很多时间。但是,在投入使用后,导出的表格却是能收到很多反馈,说内容不对。不对的地方主要体现在身份证号码之类的比较长数值,用Excel软件打开后,15位以后的数值会丢失,导致身份证号码不完整。Layui最近一两年的更新力度越来越小了,经常跳票,也不知道能活多久,只能先自己动手吧~

首先,我们用文本查看工具查看导出的内容,可以确定,导出的身份证号码是完整,但用Excel软件打开之后,就出问题了。为此,我百度了下Excel的处理机制,得知,Excel显示数字时,如果数字大于12位,它会自动转化为科学计数法,如果数字大于15位,它不仅用于科学技术法表示,还会只保留高15位,其他位都变0。

如果要解决这个问题,目前只想到一个解决方法,让Excel处理这个数据的时候,不识别它为数值。这要怎么做呢?

首先,我们先前往github下载未压缩过的代码,搜索table.exportFile = function
这个方法的原始代码如下

//表格导出
table.exportFile = function(id, data, type){
    var that = this;

    data = data || table.clearCacheKey(table.cache[id]);
    type = type || 'csv';

    var config = thisTable.config[id] || {}
        ,textType = ({
        csv: 'text/csv'
        ,xls: 'application/vnd.ms-excel'
    })[type]
        ,alink = document.createElement("a");

    if(device.ie) return hint.error('IE_NOT_SUPPORT_EXPORTS');

    alink.href = 'data:'+ textType +';charset=utf-8,\ufeff'+ encodeURIComponent(function(){
        var dataTitle = [], dataMain = [], dataTotal = [];

        //表头和表体
        layui.each(data, function(i1, item1){
            var vals = [];
            if(typeof id === 'object'){ //如果 id 参数直接为表头数据
                layui.each(id, function(i, item){
                    i1 == 0 && dataTitle.push(item || '');
                });
                layui.each(table.clearCacheKey(item1), function(i2, item2){
                    vals.push('"'+ (item2 || '') +'"');
                });
            } else {
                table.eachCols(id, function(i3, item3){
                    if(item3.field && item3.type == 'normal' && !item3.hide){
                        var content = item1[item3.field];
                        if(content === undefined || content === null) content = '';

                        i1 == 0 && dataTitle.push(item3.title || '');
                        vals.push('"'+ parseTempData(item3, content, item1, 'text') + '"');
                    }
                });
            }
            dataMain.push(vals.join(','));
        });

        //表合计
        layui.each(that.dataTotal, function(key, value){
            dataTotal.push(value);
        });

        return dataTitle.join(',') + '\r\n' + dataMain.join('\r\n') + '\r\n' + dataTotal.join(',');
    }());

    alink.download = (config.title || 'table_'+ (config.index || '')) + '.' + type;
    document.body.appendChild(alink);
    alink.click();
    document.body.removeChild(alink);
};

然后将里面的

vals.push('"'+ parseTempData(item3, content, item1, 'text') + '"');

替换成

content = parseTempData(item3, content, item1, 'text').replace(/(^\s*)|(\s*$)/g, "");
if (/^\d+$/.test(content) && content.length > 15 && type == 'xls') {
    vals.push('="'+ content + '"');
} else {
    vals.push('"'+ content + '"');
}

显示问题解决了,但不适合用于数据,但办公室的Excel大神们应该有办法吧。反正我能让他正常显示就行了,其它我不管,哈哈。

哦,对了,差点忘了标题。上面只是解决了数值大于15位会丢失尾数的问题,并没有解决科学计数法的问题。如果想不显示科学计数法,将里面的代码替换下即可。其实推荐使用上面的代码就可以了,科学计数法问题可以设置单元格格式来解决。

vals.push('"'+ parseTempData(item3, content, item1, 'text') + '"');

替换成

content = parseTempData(item3, content, item1, 'text').replace(/(^\s*)|(\s*$)/g, "");
if (/^\d+$/.test(content) && content.length > 12 && type == 'xls') {
    vals.push('="'+ content + '"');
} else {
    vals.push('"'+ content + '"');
}

最近有做一个项目,需要根据用户当前位置自动填写省市区,然后心里有选择:H5原生定位、百度地图、腾讯地图和高德地图。
既然是做公众号,还是比较偏向用腾讯自家的地图--腾讯地图。不是因为它好,主要就是怕用其它的不稳定。
为什么呢?主要怕腾讯那一天搞什么限制,限制使用其它地图,倒是定位功能无法正常使用。
觉得多虑的话,可以想想淘宝抖音为什么在微信打不开。好了,不说这么多废话了,回归正题~

一、申请key

申请网址:https://lbs.qq.com/dev/console/key/manage
调用地图服务需要用到KEY,所以需要申请。申请流程也很简单,不用怎么说了,直接打开上面的网址申请即可。

二、引入JS

<script charset="utf-8" src="https://apis.map.qq.com/tools/geolocation/min?key={你的KEY}&referer={你的网站名}"></script>

三、Javascript调用代码

官方有提供三种用法,几种用法经过测试,第三种相对比较稳定,所以这里写的是第三种用法。
官方文档:https://lbs.qq.com/tool/component-geolocation.html
第一次尝试根据GPS定位,如果失败(用户拒绝了获取精确位置),则尝试根据IP地址定位。
获取成功后,直接根据返回对象里数据拼接即可

let geolocation = new qq.maps.Geolocation();
geolocation.getLocation(
    // 获取成功回调
    function (position) {
        // {"module":"geolocation","type":"cache","adcode":"4402**","nation":"中国","province":"广东省","city":"韶关市","district":"**区","addr":"***","lat":24.***57,"lng":113.***708,"accuracy":3720}
        console.log(position);
    },
    // 获取失败回调
    function () {
        console.info('获取精确定位失败,尝试通过IP地址获取位置信息');

        geolocation.getIpLocation(
            // 获取成功回调
            function (position) {
                // {"module":"geolocation","adcode":440204,"type":"ip","nation":"中国","province":"广东省","city":"韶关市","district":"","addr":"","lat":24.80446,"lng":113.61095,"accuracy":10000}
                console.log(position);
            },
            // 获取失败回调
            function () {
                console.info('尝试通过IP地址获取位置信息失败');
                alert("您的当前位置获取失败,请手动填写安装地区");
            }
        )

    },
    {
        // 获取定位超时时间,超过这个时间则直接失败,单位:秒
        timeout: 30,
        failTipFlag: true
    }
);

字段宽度

名称示例值正常尺寸小尺寸大尺寸
日期时间2019-01-01 00:00:00160142
日期时间2019-01-01...118
日期2019-01-0110692
文字名字5854
文字处理中7368
文字王者荣耀8678
文字超级马里奥 90
按钮编辑6563
按钮编辑 删除115100
按钮编辑 删除 日志158132
按钮编辑 删除 日志 详情 158
数字13888888888118105
数字99999.99 82
数字999999 72
数字999.9 62

内容

<div class="layui-fluid">
    <div class="layui-card">
        <form class="layui-form layui-card-header layuiadmin-card-header-auto search">
            <div class="layui-form-item">
                <div class="layui-inline">
                    <input type="number" name="id" value="" placeholder="请输入预约ID" class="layui-input">
                </div>
                <div class="layui-inline">
                    <input type="number" name="user_id" value="" placeholder="请输入用户ID" class="layui-input">
                </div>
                <div class="layui-inline">
                    <input type="text" name="name" value="" placeholder="请输入姓名" class="layui-input">
                </div>
                <div class="layui-inline">
                    <input type="text" name="tel" value="" placeholder="请输入电话号码" class="layui-input">
                </div>
                <div class="layui-inline">
                    <input type="text" name="area" value="" placeholder="请输入安装地区" class="layui-input">
                </div>
                <div class="layui-inline">
                    <input type="text" name="address" value="" placeholder="请输入详细地址" class="layui-input">
                </div>
                <div class="layui-inline">
                    <select name="product_id" lay-search>
                        <option value="">请选择产品</option>
                    </select>
                </div>
                <div class="layui-inline">
                    <select name="status">
                        <option value="">请选择状态</option>
                        <option value="0">已取消</option>
                        <option value="1">待派单</option>
                        <option value="2">已接单</option>
                        <option value="3">已安装</option>
                    </select>
                </div>
            </div>
        </form>
        <div class="layui-card-body">
            <table class="layui-hide" id="table" lay-filter="table"></table>
        </div>
    </div>
</div>

内容模板

<script type="text/html" id="status">
    {{#  switch(d.status){ case 0:}}
    删除
    {{#  break; case 1:}}
    <span style="color: #1E9FFF"><i class="layui-icon layui-icon-friends"></i>&nbsp;在籍</span>
    {{#  break; case 2:}}
    <span style="color: #999999"><i class="layui-icon layui-icon-friends"></i>&nbsp;退学</span>
    {{#  break; case 3:}}
    转校
    {{#  break; case 4:}}
    <span style="color: #FF5722"><i class="layui-icon layui-icon-friends"></i>&nbsp;毕业</span>
    {{#  } }}
</script>
<script type="text/html" id="toolbar">
    <a class="layui-btn layui-btn-xs" lay-event="view">查看</a>
    <a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete">删除</a>
</script>

JavaScript

layui.use(['table', 'jquery', 'layer', 'form'], function(){
    let table   = layui.table,
        $       = layui.jquery,
        form    = layui.form;

    // 获取数据并渲染表格
    table.render({
        elem: '#table'
        ,url: location.href
        ,method: 'post'
        ,id: 'table'
        ,toolbar: false
        ,cols: [[
            {type: 'checkbox', fixed: 'left'}
            ,{field:'id', title: 'ID', width:68}
            ,{field:'user_id', title: '用户', width:168, templet: '#user_id'}
            ,{field:'name', title: '姓名', width:86}
            ,{field:'tel', title: '手机号码', width:120}
            ,{field:'area', title: '安装地区', width:138}
            ,{field:'address', title: '详细地址', width:138}
            ,{field:'install_date', title: '安装日期', width:138}
            ,{field:'product_id', title: '产品', width:138}
            ,{field:'birthday', title: '出生年月日', width:106}
            ,{field:'create_time', title: '时间', width:160}
            ,{field:'status', title: '状态', width:80, templet: '#status'}
            ,{field:'options', title: '操作', width:118, toolbar: '#toolbar', fixed: 'right'}
        ]]
        ,where: getSearchWhere('form')
        ,page: true
        ,height: 'auto'
    });

    table.on('tool(table)', function(obj){
        switch (obj.event) {
            case 'view':
                layer.open({
                    type: 2
                    ,title: '查看内容'
                    ,content: "{:url('merchant/Feedback/view')}?id=" + obj.data.id
                    ,area: ['600px', '500px']
                    ,btn: ''
                    ,end: function () {
                        // 重载表格
                        table.reload('table');
                    }
                });
                break;
            case 'delete':
                layer.confirm('确定要删除 ' + obj.data.id + ' ?', function(index){
                    $.post("{:url('merchant/Feedback/delete')}", {id: obj.data.id}, function (data) {
                        layer.msg(data.msg);

                        if (data.code == 0) {
                            // 重载表格
                            table.reload('table');
                        }
                    });

                    layer.close(index);
                });

                break;
            case 'icon':
                layer.photos({
                    photos: {
                        "title": "预览",
                        "data": [
                            {"src": obj.data.icon,}
                        ]
                    }
                });
                break;
        }
    });

    $('#search').click(function () {
        table.reload('table', {
            where: getSearchWhere('form')
        });
    });

    form.on('select(search)', function(){
        table.reload('table', {
            where: getSearchWhere('.search')
        });
    });
    $('.search input').change(function () {
        table.reload('table', {
            where: getSearchWhere('.search')
        });
    });

    function getSearchWhere(form_ele) {
        let data = {};
        $.each($(form_ele).serializeArray(), function (key, value) {
            data[value.name] = value.value;
        });

        return data;
    }
});

在使用input propertychange事件时,遇到一个问题。我输入一个字时,会重复执行五六次事件,事件里又包含了网络请求,体验非常差。经过搜索,找到了解决办法,详情如下。

代码

// 监听textarea的输入
$(document).on('input propertychange', 'textarea', function () {
    var detailsElement = $(this),
        details = $(this).val();
    // 确保是propertychange事件,并且是改变了内容
    if (window.event && event.type == 'propertychange' && event.propertyName != 'value')
        return;

    // 清除旧的定时器
    window.clearTimeout($(this).data('timeout'));
    // 设置新的定时器
    $(this).data('timeout', setTimeout(function () {
        // 这里放置要执行的代码
        console.log('值改变了~输入值:' + details);
    }, 5000)); // 延时值:5000 = 5秒
});

原理

1.监听textarea多行文本输入框的inputpropertychange事件
2.事件触发后,判断是否是propertychange事件,并且是改变内容的propertychange事件
3.清除旧的定时器,然后设置新的定时器。这样在一定时间内,回调函数不会重复执行,只会执行一次。

最近有个做招聘网站的客户提出了个修改要求,要求报名列表上的某个元素可点击,点击后可以录取这个人。
这不是日了个狗了嘛,现在的列表项的每项是用a标签包着的,并且是多处调用这里,所以不能将a标签改成其它。
不过也得满足不是。
经过一番查找,找到一个方法:阻止冒泡事件

代码如下:

<div class="list">
    <a href="" class="list-item">
        麻花藤<br/>
        2018-10-15 18:52:33<br/>
        <!-- 给span元素加上pass类,点击这丫的录取此人 -->
        <span class="pass">点击录取</span>
    </a>
    <a href="" class="list-item">
        马云<br/>
        2018-10-15 18:52:33<br/>
        <span class="pass">点击录取</span>
    </a>
    <a href="" class="list-item">
        王健林<br/>
        2018-10-15 18:52:33<br/>
        <span class="pass">点击录取</span>
    </a>
</div>
<script>
// 这里用了JQuery,很多人说过时了,但我还是挺喜欢用的,方便!
$(document).on('click', '.pass', function (e) {
    // 这里执行你要执行的动作,例如请求同意录取接口
    // .....

    // 阻止冒泡事件
    e.stopPropagation();
    // 取消默认动作
    return false;
});
</script>