小程序历史用户列表

继上一篇的小程序文档博客,这篇博客才算是真正的开始吧。

先看看显示效果

这里直接按设计图设计的,大部分内容也不难,就不详细写了。主要有个问题就是 iconfont 的使用,并不能把它当成 icon 设置属性,图片的属性需要通过 font-size 和 color 来设置。
在这里插入图片描述
在这里插入图片描述

登录下拉框的实现

登录界面没什么难度,这里稍微复杂点的就是这个下拉框的实现了,直接看代码。

  • HTML
<view class="input-container">

    <!-- 下拉的历史用户 -->
    <view class='user-list-container' wx:if="{{isShowUsers}}"
        style='height:{{historyUsers.length>5?400:historyUsers.length*80}}rpx;'>

        <view class='list-item row-center' style='{{index==historyUsers.length-1&&"border:0;"}}'
            wx:for='{{historyUsers}}' wx:key='this'>
            <view style="flex:1" data-index='{{index}}' catchtap='selectUser'>
                {{item.username}}
            </view>
            <van-icon data-index='{{index}}' name="close" size="32rpx" catchtap='deleteUser' />
        </view>
    </view>

	<!-- 账号输入框 -->
    <view class="input-button-container row-center">
        <input class="input flex1" model:value="{{ username }}" type="text" placeholder="请输入用户名"
            bindinput="inputChange" />
        <view catchtap='showHistoryUsers'>
            <van-icon name="{{isShowUsers?'arrow-up':'arrow-down'}}" size="40rpx" color="#949494FF" />
        </view>
    </view>

	<!-- 密码输入框 -->
    <view class="input-button-container margin-top-24 row-center">
        <input class="input flex1" model:value="{{ password }}" password="{{!isDisplayPassword}}" placeholder="请输入密码"
            bindinput="inputChange" />
        <view catchtap="displayPassword">
            <van-icon name="{{isDisplayPassword?'eye-o':'closed-eye'}}" size="40rpx" color="#949494FF" />
        </view>
</view>
  • CSS
.input-container {
    width: auto;
    position: relative;
    margin: 0 80rpx;
    margin-top: 64rpx;
}

.user-list-container {
    height: 0;
    width: 100%;

    position: absolute;
    top: 104rpx;

    border: 2rpx solid #efefef;
    border-top: 0;
    box-sizing: border-box;
    overflow-y: auto;
    background: #fff;
    z-index: 100;

    transition: height 0.3s;
}

.list-item {
    height: 80rpx;
    border-bottom: 2rpx solid #efefef;
    padding: 10rpx 40rpx;
    box-sizing: border-box;

    font-size: 24rpx;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: #949494;
    line-height: 40rpx;
}

.input {
    height: 104rpx;
    font-size: 32rpx;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    line-height: 44rpx;
    border: 0rpx;
}

.input-button-container{
    height: 106rpx;
    overflow: hidden;
    position: relative;
    border-bottom: 2rpx solid #E5E5E5;
}
  • Page.js
Page({
    data: {
        //显示密码
        isDisplayPassword: false,
        //展示历史用户
        isShowUsers: false,

        //输入框
        username: "",
        password: "",

        historyUsers: [{
            username: '张三',
            password: '123'
        },{
            username: '李四',
            password: '123'
        },{
            username: '王麻子',
            password: '123'
        },{
            username: '赵子龙',
            password: '123'
        },{
            username: '去要钱',
            password: '123'
        },{
            username: '孙子',
            password: '123'
        }],
    },

    onLoad: function (options) {
        //读取历史用户数据
        this.loadUsers();
    },

    onShow: function () {
        if (this.data.historyUsers.length > 0) {
            let lastIdx = this.data.historyUsers.length - 1
            this.setData({
                username: this.data.historyUsers[lastIdx].username,
                password: this.data.historyUsers[lastIdx].password
            })
        }
    },

    //显示密码
    displayPassword(e) {
        this.setData({
            isDisplayPassword: !this.data.isDisplayPassword
        })
    },

    //显示历史用户列表
    showHistoryUsers() {
        if (this.data.historyUsers.length > 0) {
            this.setData({
                isShowUsers: !this.data.isShowUsers
            });
        } else {
            app.showErrToast("暂无历史用户")
        }
    },

    loadUsers() {
        let users = wx.getStorageSync("historyUsers")
        if (users) {
            users.forEach(element => {
                //解密密码
                element.password = encrypt.decryptResult(element.password, encryptInfo);
            });
            //更新显示数据
            this.setData({
                historyUsers: users
            })
        }
    },

    saveUser(user) {
        let users = this.data.historyUsers;

        //如果已经存在删除再插入到最后
        let index = -1
        for (let i = 0; i < users.length; i++) {
            let temp = users[i]
            if (user.username == temp.username) {
                index = i
                break
            }
        }
        if (index >= 0) {
            users.splice(index, 1)
        }

        //最后一个表示最近登录
        users.push(user)

        //更新显示数据
        this.setData({
            historyUsers: users
        })
        //保存到本地
        this.saveUsers();
    },

    //深拷贝数组,修改密码保存
    saveUsers() {
        let users = this.data.historyUsers;
        let encryptUsers = []
        users.forEach(element => {
            encryptUsers.push({
                username: element.username,
                password: encrypt.encryptParams(element.password, encryptInfo)
            })
        });
        //储存到本地
        wx.setStorageSync("historyUsers", encryptUsers);
    },

    selectUser(e) {
        let idx = e.currentTarget.dataset.index;
        let user = this.data.historyUsers[idx];
        this.setData({
            username: user.username,
            password: user.password,
            isShowUsers: false
        });
    },

    deleteUser(e) {
        let that = this

        let index = e.currentTarget.dataset.index
        let users = that.data.historyUsers
        let name = users[index].username

        wx.showModal({
            content: '确认删除' + name + '?',
            success: function (res) {
                if (res.confirm) {

                    //从数组中删除,改变数组大小
                    users.splice(index, 1)
                    //更新显示数据
                    that.setData({
                        historyUsers: users,
                        isShowUsers: !that.data.isShowUsers
                    });
                    //保存到本地
                    that.saveUsers();
                } else if (res.cancel) {
                    //do nothing;
                }
            }
        })
    },

    // 登录成功	
    onLoginSuccess(res, user, password) {
        //保存用户
        this.saveUser({
            username: user,
            password: password
        })
    },
})

这里把代码删减了一些,也没测测行不行,但是这节主要功能应该都在这了,下面详细讲讲。

历史用户框的列表

列表的渲染和安卓有很大的不同,简单了很多,也就是不用自己写适配器了,可以直接双向绑定,妈妈啊,我也想再安卓里面直接这么用。

先看列表的官方文档

https://developers.weixin.qq.com/miniprogram/dev/reference/wxml/list.html

下面是代码,注意 index 和 item 的使用

<view class='list-item row-center' style='{{index==historyUsers.length-1&&"border:0;"}}'     wx:for='{{historyUsers}}' wx:key='this'>
    <view style="flex:1" data-index='{{index}}' catchtap='selectUser'>
        {{item.username}}
    </view>
    <van-icon data-index='{{index}}' name="close" size="32rpx" catchtap='deleteUser' />
</view>

历史用户框显示与隐藏

从前面的图可以看到,这里的历史用户框是需要隐藏与显示的,这里使用wx:if条件渲染。在 Page 代码中添加 isShowUsers 变量,点击账号框右边的 icon 触发 showHistoryUsers 方法,显示的同时把高度从零变大,做出一种动画效果。

Page({
    data: {
        //展示历史用户
        isShowUsers: false,
        historyUsers: [{
            username: '张三',
            password: '123'
        },]
	}

	//显示历史用户列表
    showHistoryUsers() {
        if (this.data.historyUsers.length > 0) {
            this.setData({
                isShowUsers: !this.data.isShowUsers
            });
        } else {
            app.showErrToast("暂无历史用户")
        }
    },
})

注意这里用 view 将 icon 包裹起来,扩大点击范围,并阻止点击事件向下穿透。

<view class="input-button-container row-center">
    <input class="input flex1" model:value="{{ username }}" type="text" placeholder="请输入用户名" bindinput="inputChange" />
    <view catchtap='showHistoryUsers'>
        <van-icon name="{{isShowUsers?'arrow-up':'arrow-down'}}" size="40rpx" color="#949494FF" />
    </view>
</view>

这里动态的设置了历史用户可显示的最多数目,不超过五条有多少显示多少,超过五条,只显示五条。

<!-- 下拉的历史用户 -->
<view class='user-list-container' wx:if="{{isShowUsers}}"
    style='height:{{historyUsers.length>5?400:historyUsers.length*80}}rpx;'>

    <view class='list-item row-center' style='{{index==historyUsers.length-1&&"border:0;"}}' wx:for='{{historyUsers}}'
        wx:key='this'>
        <view style="flex:1" data-index='{{index}}' catchtap='selectUser'>
            {{item.username}}
        </view>
        <van-icon data-index='{{index}}' name="close" size="32rpx" catchtap='deleteUser' />
    </view>
</view>

这里的动画,就css中最后一句生效的。

.user-list-container {
    height: 0;
    width: 100%;

    position: absolute;
    top: 104rpx;

    border: 2rpx solid #efefef;
    border-top: 0;
    box-sizing: border-box;
    overflow-y: auto;
    background: #fff;
    z-index: 100;

    transition: height 0.3s;
}

历史用户数据的保存

历史用户肯定是保存在本地的,这里需要用到微信的存储功能,下面是官方文档

https://developers.weixin.qq.com/miniprogram/dev/api/storage/wx.setStorage.html

这里我们需要保存的是登录成功的单个用户数据,但是并没有可以修改保存内容的功能,这就意味着我们要保存整个历史用户数组,其实都一样。

这里因为涉及到密码,公司要求要加密一下。需要注意的是不能直接对原始数组修改,因为对象是唯一的,把密码加密了,显示的时候也就是加密密码了。所以,应该把数据深拷贝一份,也就是重新构建一个对象,就两个字段,不麻烦。

    //深拷贝数组,修改密码保存
    saveUsers() {
        let users = this.data.historyUsers;
        let encryptUsers = []
        users.forEach(element => {
            encryptUsers.push({
                username: element.username,
                password: encrypt.encryptParams(element.password, encryptInfo)
            })
        });
        //储存到本地
        wx.setStorageSync("historyUsers", encryptUsers);
    },

这里有一个如何记住最新用户的逻辑,我这写的就简单了,保存的时候先遍历一遍历史用户数组,将已有用户删除,再将新数据添加到末尾。其实这是对的,因为这样写,如果密码更新了,保存的就是准确数据而不是过时数据。

还有就是 splice 函数还是值得一说的,删除一个元素后,这个函数会将数组移动,保持正确的顺序,不然出现一个空的数据真的很头疼。

    saveUser(user) {
        let users = this.data.historyUsers;

        //如果已经存在删除再插入到最后
        let index = -1
        for (let i = 0; i < users.length; i++) {
            let temp = users[i]
            if (user.username == temp.username) {
                index = i
                break
            }
        }
        if (index >= 0) {
            users.splice(index, 1)
        }

        //最后一个表示最近登录
        users.push(user)

        //更新显示数据
        this.setData({
            historyUsers: users
        })
        //保存到本地
        this.saveUsers();
    },

历史用户数据的载入

历史数据的载入很简单,和保存类似,用同样的 key 取出数据就是了。

    loadUsers() {
        let users = wx.getStorageSync("historyUsers")
        if (users) {
            users.forEach(element => {
                //解密密码
                element.password = encrypt.decryptResult(element.password, encryptInfo);
            });
            //更新显示数据
            this.setData({
                historyUsers: users
            })
        }
    },

历史用户数据的删除

历史数据的删除就有点讲头了,虽然叫删除,但是实际上不就是不保存删除的数据么,这样想就简单了。和前面一样使用 splice 函数,去除该项再保存就好,这里有个问题就是获取选中项的index。

前面我们讲到了 index 的使用,这个就是我们选中先要的。

<view class='list-item row-center' style='{{index==historyUsers.length-1&&"border:0;"}}'     wx:for='{{historyUsers}}' wx:key='this'>
    <view style="flex:1" data-index='{{index}}' catchtap='selectUser'>
        {{item.username}}
    </view>
    <van-icon data-index='{{index}}' name="close" size="32rpx" catchtap='deleteUser' />
</view>

data-index在这个view绑定了index这个数据,catchtap的方法在点击的时候就能获取这个数据

data-index='{{index}}'
catchtap='deleteUser'

这里用了一个对话框确认一下还是很有必要的,删除数据后调用前面保存的方法就可以了

   deleteUser(e) {
        let that = this

        let index = e.currentTarget.dataset.index
        let users = that.data.historyUsers
        let name = users[index].username

        wx.showModal({
            content: '确认删除' + name + '?',
            success: function (res) {
                if (res.confirm) {

                    //从数组中删除,改变数组大小
                    users.splice(index, 1)
                    //更新显示数据
                    that.setData({
                        historyUsers: users,
                        isShowUsers: !that.data.isShowUsers
                    });
                    //保存到本地
                    that.saveUsers();
                } else if (res.cancel) {
                    //do nothing;
                }
            }
        })
    },

历史用户数据的选择

选择没什么好说的,就是记得选中后关闭下拉框就好

    selectUser(e) {
        let idx = e.currentTarget.dataset.index;
        let user = this.data.historyUsers[idx];
        this.setData({
            username: user.username,
            password: user.password,
            isShowUsers: false
        });
    },

动态切换密码显示

实际上上面贴的代码,还有一个动态切换密码显示功能,点击密码右边的按钮切换显示密码。

js代码很简单,只是切换了 isDisplayPassword 这个属性的值

    //显示密码
    displayPassword(e) {
        this.setData({
            isDisplayPassword: !this.data.isDisplayPassword
        })
    },

而在HTML代码中,需要根据 isDisplayPassword 这个属性值,切换显示的图标,以及 input 组件的 password 属性,很简单啊。

<view class="input-button-container margin-top-24 row-center">
    <input class="input flex1" model:value="{{ password }}" password="{{!isDisplayPassword}}" placeholder="请输入密码"
        bindinput="inputChange" />
    <view catchtap="displayPassword">
        <van-icon name="{{isDisplayPassword?'eye-o':'closed-eye'}}" size="40rpx" color="#949494FF" />
    </view>
</view>

结语

到这里,下拉显示历史账号的功能就告一段落了,用起来还是挺秀的。

end
完美撒花

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值