好久都没有写东西了,现在干的活都是重复和简单的活,能总结出来的东西还是不太多。
目前做电商平台,其中用到选择地址的控件,不过不是自己写的,最近花时间重新自己做一个,目前就先吧功能样式,功能完成第一版,之后再进行优化和升级,最终做成组件或者是插件形式,调用只需要几行代码去完成,不过这些都是后话了,目前显示完成基本的样子和功能。这一篇文章就当做写东西的一个笔记,记录一个过程。
先放上出来的效果
看效果图挺简单的,因为懒。就用了 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+’,"’+data[i].name+’")”>’+data[i].name+'</p>’;
}else{
html += ‘<p id=”add_’+data[i].areaId+'” onclick=”chooseDetail(‘+data[i].areaId+’,’+addressNum+’,"’+data[i].name+’")”>’+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)+’,"’+data[i].name+’")”>’+data[i].name+'</p>’;
}
}
$(“#”+adid2).append(html);
}
以上三步就完成了地址选择粗糙版的构造,其中用来请求数据的方法写了两个,拼接 html 渲染页面的方法也写了两个,这些是有点冗余的,这个部分之后可以合成一个。
目前优化的构思是有,不过还没来得及实施,得找时间做一下,优化的思路是其中的方法先进行相应的优化,最后集成成一个对象,在页面调用的时候只要把初始化数据传入,最后加上一个回调方法,将选择完成的地址返回回来,这样整个页面也呢个简洁很多,调用方法也简单了,使用起来的话会方便很多。
因为目前我写的 vue 的单页面应用,用到 keepAlive,所以现有的控件总是出问题,等这两天优化完进行测试下,到时候在写一篇简单点的文章发布出来。
能看到这里的,大家要是有什么问题的可以留言跟我讨论讨论,有啥好的想法也可以跟我沟通,大家一起学习。
以上