web学习笔记15-移动端地址选择功能@v1.0简单版

    好久都没有写东西了,现在干的活都是重复和简单的活,能总结出来的东西还是不太多。

    目前做电商平台,其中用到选择地址的控件,不过不是自己写的,最近花时间重新自己做一个,目前就先吧功能样式,功能完成第一版,之后再进行优化和升级,最终做成组件或者是插件形式,调用只需要几行代码去完成,不过这些都是后话了,目前显示完成基本的样子和功能。这一篇文章就当做写东西的一个笔记,记录一个过程。

    先放上出来的效果


成果gif

    看效果图挺简单的,因为懒。就用了jquery加js,方法什么的也没考虑性能啥的,就初步先做一个出来。后面再慢慢一步步优化。

    不愿意往下看的有兴趣的可以直接看这里 githubd selectAddress-v1.0地址

    接下来我们进入正题!有什么问题可以留言跟我讨论,这个功能不是很复杂,只是作为粗糙版就没有考虑很多。

第一步:构思功能样子,先有概念!

    首先至少得有想法,做成什么样子,这个很重要,要是会点设计,可以自己先做个大概的图或者原型,既然之后要做成组件,首先页面上就得有个按钮,然后弹出选择地址的弹框,页面上得有一个显示选择完地址的标签。
    弹框出来之后,得有几个部分,一个是顶部标题,叉叉按钮用来隐藏,接下来是每级选择完的地址显示在中间,然后就是下面的每级地址列表,并且列表中若有选中的地址则标红,这些都是最基本的。
    我这边做的地址目前只有四级地址,不会有更深层次的地址,所以只有四列。构思好了,大概样子就是下图。


未弹出选择框
弹出选择框

第二步:构思完之后就是构造页面

    构造页面算是最简单的部分了,就是写html,css了。写成上图的样子。

    因为四级地址列表考虑到多次切换留有缓存的问题,没有做成每切换一次就请求一次,而是做成四个列表,通过隐藏显示的方式来更方便的操作。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0,minimum-scale=1, maximum-scale=1"/>
    <link rel="stylesheet" href="address.css">
    <script src="jquery-3.2.1.min.js"></script>
</head>
<body>
<div class="btn" onclick="show()">点击选择地址</div>

<div class="show_address" id="product_address_show" onclick="show()">北京市,北京市,朝阳区,朝外街道</div>

<div id="yls_address_choose" style="display: none">
    <div class="yls_address_bg" onclick="hide()"></div>
    <div class="yls_address_main">
        <div class="yls_address_pop_top">
            <div class="yls_address_pop_title">请选择地址</div>
            <div class="yls_address_pop_cancel" onclick="hide()"></div>
        </div>
        <div class="yls_address_pop_main">
            <div class="yls_address_product">
                <div class="yls_address_select" id="yls_address_select">
                    <div class="yls_address_top_address jdshop_alignment_middle">
                        <div id="yls_top_address_1">请选择</div>
                        <div id="yls_top_address_2"></div>
                        <div id="yls_top_address_3"></div>
                        <div id="yls_top_address_4"></div>
                    </div>
                    <div class="yls_address" id="yls_address_1"></div>
                    <div class="yls_address" id="yls_address_2"></div>
                    <div class="yls_address" id="yls_address_3"></div>
                    <div class="yls_address" id="yls_address_4"></div>
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>

    这个html还是一目了然的,很简单,下面是css样式。


body, html {
    -webkit-user-select: none;
    user-select: none
}
html {
    -webkit-text-size-adjust: 100%
}
body {
    line-height: 1.6;
    background-color: #f5f5f9;
    color: #4a4a4a;
    font-size: 14px;
    font-family: Arial, '微软雅黑', Helvetica Neue, Helvetica, sans-serif;
    -webkit-overflow-scrolling: touch;
    overflow-scrolling: touch
}
* {
    margin: 0;
    padding: 0
}
a img {
    border: 0
}
a {
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
    -webkit-appearance: none
}
@font-face {
    font-weight: 400;
    font-style: normal;
    font-size: 14px;
    font-family: Arial, '微软雅黑', Helvetica Neue, Helvetica, sans-serif
}
input, textarea {
    border: 0;
    outline: 0;
    -webkit-appearance: none;
    -webkit-tap-highlight-color: transparent;
    font-size: inherit;
    color: inherit
}

/*点击选择按钮*/
.btn{
    margin: 0 auto;
    width: calc(50%);
    height: 30px;
    margin-top: 100px;
    background-color: lightcyan;
    line-height: 30px;
    text-align: center;
    font-size: 14px;
}
.alignment_middle{
    -webkit-box-align: center;
    -webkit-align-items: center;
    align-items: center;
    -webkit-box-pack: start;
    -webkit-justify-content: flex-start;
    justify-content: flex-start;
    display: -webkit-box;
    display: -webkit-flex;
    display: flex;
}
/*显示文字*/
.show_address{
    margin: 0 auto;
    margin-top: 10px;
    width: 80%;
    height: 30px;
    background-color: #fff;
    text-align: center;
    line-height: 30px;
    font-size: 14px;
}

/*背景*/
.yls_address_bg {
    position: fixed;
    top: 0;
    left: 0;
    height: 100%;
    width: 100%;
    background: #000;
    z-index: 500;
    opacity: .3;
    -webkit-transition: opacity .3s;
    transition: opacity .3s;
    touch-action: none
}
/*主弹框*/
.yls_address_main {
    position: fixed;
    left: 0;
    width: 100%;
    bottom: 0;
    background: #fff;
    border-radius: 10px 10px 0 0;
    box-shadow: 0 0 3px #e9e9e9;
    -webkit-transform: translate3d(0, 120%, 0);
    transform: translate3d(0, 120%, 0);
    -webkit-transition: -webkit-transform .3s;
    transition: -webkit-transform .3s;
    transition: transform .3s;
    transition: transform .3s, -webkit-transform .3s;
    z-index: 1001;
    transform: translate3d(0, 0, 0);
}
.yls_address_pop_top {
    text-align: center;
    height: 50px;
    margin-bottom: 5px;
}
.yls_address_pop_title {
    height: 100%;
    line-height: 50px;
}
.yls_address_pop_cancel {
    position: absolute;
    right: 0;
    top: 0;
    width: 50px;
    height: 50px;
}
.yls_address_pop_cancel::before, .yls_address_pop_cancel::after {
    content: '';
    width: 16px;
    height: 1px;
    background: #000;
    display: block;
    position: absolute;
    right: 10px;
    top: 25px;
}
.yls_address_pop_cancel::before {
    transform: rotate(45deg); /*进行旋转*/
}
.yls_address_pop_cancel::after {
    transform: rotate(-45deg);
}
.yls_address_pop_main {

}
.yls_address_product{

}
.yls_address_select{
    height: calc(60vh);
    width: 100%;
    position: relative;
    overflow: hidden;
}
.yls_address_top_address{
    font-size: 12px;
    height: 35px;
    overflow: hidden;
    border-bottom: 1px solid #ddd;
}
.yls_address_top_address>div{
    padding: 5px 5px;
    margin: 0 5px;
    white-space: nowrap;
}
.yls_address_top_address>div.show{
    color: #c91623;
    border-bottom: #c91623 1px solid;
}
.yls_address{
    position: absolute;
    left: 0;
    top: 45px;
    overflow: auto;
    width: 100%;
    height: calc(60vh - 35px);
    -webkit-transform: translate3d(-100%,0,0);
    transform: translate3d(-100%,0,0);
    -webkit-transition: -webkit-transform .3s .2s;
    transition: -webkit-transform .3s .2s;
    transition: transform .3s .2s;
    transition: transform .3s .2s,-webkit-transform .3s .2s;
}
.yls_address p{
    padding: 8px 10px;
    font-size: 14px;
}
.yls_address p.p_show {
    position: relative;
    color: #c91623;
}
.yls_address.show {
    -webkit-transform: translate3d(0,0,0);
    transform: translate3d(0,0,0);
}

    css上半部分是一些基本的初始化浏览器样式,下面部分就是地址选择的样式,目前还没加入动态效果,之后优化部分考虑做进去。不过这部分的样式完全可以自己按照自己的喜好做,想做成什么样子就做成什么样子的。

第三步 :逻辑部分

    这个部分算是最重要的,不过在此重申一遍,我做的只是粗糙的版本,逻辑部分是没有经过任何优化的,这个大家可以按照自己优化的方式进行优化,后期我会做成插件形式再写一篇。😂希望看到这篇文章的大家不要嘲笑我写的粗糙,毕竟我写这个也只是给新手看看,不要嫌弃。

1.做基本的变量声明工作

  /*赋初始值*/
    var startId = [1804,1805,1829,1831];
    var startName = ['北京市','北京市','朝阳区','朝外街道'];

    //最终获取到的值
    var returnStartId = [];
    var returnStartName = [];

2.做弹出弹框的弹出隐藏方法

/*显示地址选择,隐藏地址选择*/
    function show() {
        document.getElementById("yls_address_choose").style.display="";//显示
        var url = 'http://*********/address/areas?areaId=';//这边写你请求接口的url
        initAddress(url,startId,startName);//初始化工作的方法
    }

    /*隐藏地址选择*/
    function hide() {
    //点击隐藏的时候循环将列表所有的show样式去除,重新添加到最后一列上
        for(var i = 1;i < 5;i++){
            var ad = 'yls_top_address_' + i;
            var adid = 'yls_address_' + i;
            $("#"+ad).removeClass('show');
            $("#"+adid).removeClass('show');
            $("#"+ad).show();
            $("#"+adid).show();
        }
        document.getElementById("yls_address_choose").style.display="none";//显示
        //点击隐藏了,就把最终值还原成初始值
        returnStartId = startId;
        returnStartName = startName;
    }

3.做弹出弹框的初始化工作

 //初始化方法
    function initAddress(url,startId,startName) {
        //将我们最后需要获取的值初始化成初始值
        returnStartId = startId;
        returnStartName = startName;
        //初始化请求areaid=0的数据,我用的接口areaid=0的时候是请求省级地址
        request(url,0,1);
    }

     //初始化请求数据部分,
    //thisNum 为areaid变化数值 url是请求url, addressNum是每个address是第几个
    function request(url,thisNum,addressNum){
        var addressUrl = url+ thisNum;
        $.ajax({
            type: 'get',
            url: addressUrl,
            dataType: "json",
            success: function (res) {
                //无常规错误,根绝data数据做具体的业务判断显示
                console.log(res.result);
                //初始化的渲染html
                setHtml(res.result,thisNum,addressNum);
                //循环请求下级地址
                if(addressNum < startId.length){
                    request(url,startId[addressNum-1],addressNum+1);
                    addressNum += 1;
                }
            },
            error: function erryFunction(err) {
                //网络请求错误
                console.log(err);
                console.log('读取失败')
            }
        });
    }

    //初始化渲染页面
    function setHtml(data,thisNum,addressNum) {
        var addressId = 'yls_address_' + addressNum;
        var topAddress = 'yls_top_address_' + addressNum;
        if(addressNum == startId.length){
            $("#"+addressId).addClass('show');
            $("#"+topAddress).addClass('show');
        }
        $("#"+topAddress).text(startName[addressNum-1]);

        //初始化之后选中的地址顶部tab进行添加点击方法,每次点击会做什么事情
        document.getElementById(topAddress).addEventListener("click",function () {
            var a = parseInt(topAddress.substr(topAddress.length-1,1));
            console.log(a);
            for(var i = 1;i < 5;i++){
                var ad = 'yls_top_address_' + i;
                var adid = 'yls_address_' + i;
                if(i != a){
                    $("#"+ad).removeClass('show');
                    $("#"+adid).removeClass('show');
                    if(i > a){
                        $("#"+ad).hide();
                    }
                }else{
                    $("#"+ad).addClass('show');
                    $("#"+adid).addClass('show');
                }
            }

            //tab上选中地址点击的时候,最终选择地址数组数据也要相应的变化
            returnStartId = returnStartId.slice(0,addressNum);
            returnStartName = returnStartName.slice(0,addressNum);
           
        },false);
        $("#"+addressId).empty();//清空当前列表的html
        var html = '';
        //拼接html,为地址列表中每一个地址添加点击方法
        if(data){
            for(var i = 0;i < data.length;i++){
                if(startName[addressNum-1] == data[i].name){
                    html += '<p class="p_show" id="add_'+data[i].areaId+'" onclick="chooseDetail('+data[i].areaId+','+addressNum+',&quot;'+data[i].name+'&quot;)">'+data[i].name+'</p>';
                }else{
                    html += '<p id="add_'+data[i].areaId+'" onclick="chooseDetail('+data[i].areaId+','+addressNum+',&quot;'+data[i].name+'&quot;)">'+data[i].name+'</p>';
                }
            }
        }
        //添加html到列表上渲染页面
        $("#"+addressId).append(html);
    }

4.每次点选地址之后的具体逻辑

     //点击列表中详细地址的方法
    function chooseDetail(areaId,addressNum,name) {
        var url = 'http://******/address/areas?areaId=';
        var adid = 'add_'+areaId;
        var adid1 = 'yls_address_' + addressNum;
        //选中的数据加上标红显示
        $("#"+adid1+'>p').removeClass('p_show');
        $("#"+adid).addClass('p_show');

        //点击具体地址之后,将最终选择地址数组中相应位置的数据替换掉
        returnStartId[addressNum-1] = areaId;
        returnStartName[addressNum-1] = name;
        
        //判断是否是第四级地址,如果是第四级地址,把获取到的数据渲染到页面上,并且隐藏弹框
        //如果是第四级地址,发送请求获取下一级的数据进行渲染页面
        if(addressNum == 4){
            var topAddress1 = 'yls_top_address_' + addressNum;
            $("#"+topAddress1).text(name);
            $("#product_address_show").text(returnStartName);
            hide();
        }else{
            newrequest(url,areaId,addressNum,name);
        }
    }


    //点击列表里具体地址,发送新的请求获取下一级数据
    //thisNum 为areaid变化数值 url是请求url, addressNum是每个address是第几个,name是你选择的地址具体名称
    function newrequest(url,thisNum,addressNum,name){
        var addressUrl = url+ thisNum;
        $.ajax({
            type: 'get',
            url: addressUrl,
            dataType: "json",
            success: function (res) {
                //无常规错误,根绝data数据做具体的业务判断显示
                console.log(res.result);
                //获取到数据之后渲染下一级列表
                setHtml2(res.result,thisNum,addressNum,name);
            },
            error: function erryFunction(err) {
                //网络请求错误
                console.log(err);
                console.log('读取失败')
            }
        });

    }

    //选择详细地址请求获取数据之后渲染方法
    function setHtml2(data,thisNum,addressNum,name) {
        //获取到相应的div
        var adid1 = 'yls_address_' + addressNum;
        var adid2 = 'yls_address_' + (addressNum+1);
        var topAddress1 = 'yls_top_address_' + addressNum;
        var topAddress2 = 'yls_top_address_' + (addressNum+1);

        //清空相应的下一级div和下一级tab上选中的地址,填入新的数据
        $("#"+topAddress2).empty();
        $("#"+adid2).empty();
        $("#"+topAddress2).addClass('show');
        $("#"+topAddress2).show();
        $("#"+topAddress1).removeClass('show');
        $("#"+adid2).addClass('show');
        $("#"+adid1).removeClass('show');
        $("#"+topAddress2).text('请选择');
        $("#"+topAddress1).text(name);
        var html = '';
        if(data){
            //拼接html,并且添加上新的详细地址选择方法
            for(var i = 0;i < data.length;i++){
                html += '<p id="add_'+data[i].areaId+'" onclick="chooseDetail('+data[i].areaId+','+(addressNum+1)+',&quot;'+data[i].name+'&quot;)">'+data[i].name+'</p>';
            }
        }
        $("#"+adid2).append(html);
    }

    以上三步就完成了地址选择粗糙版的构造,其中用来请求数据的方法写了两个,拼接html渲染页面的方法也写了两个,这些是有点冗余的,这个部分之后可以合成一个。
    目前优化的构思是有,不过还没来得及实施,得找时间做一下,优化的思路是其中的方法先进行相应的优化,最后集成成一个对象,在页面调用的时候只要把初始化数据传入,最后加上一个回调方法,将选择完成的地址返回回来,这样整个页面也呢个简洁很多,调用方法也简单了,使用起来的话会方便很多。
    因为目前我写的vue的单页面应用,用到keepAlive,所以现有的控件总是出问题,等这两天优化完进行测试下,到时候在写一篇简单点的文章发布出来。
    能看到这里的,大家要是有什么问题的可以留言跟我讨论讨论,有啥好的想法也可以跟我沟通,大家一起学习。

以上

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,783评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,396评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,834评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,036评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,035评论 5 362
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,242评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,727评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,376评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,508评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,415评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,463评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,140评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,734评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,809评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,028评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,521评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,119评论 2 341

推荐阅读更多精彩内容