用户体验
先上设计稿
查看偏好信息 编辑偏好信息
用户体验优化点分析和代码实现:
- 1.点击编辑时尽量控制页面高度不变,这样用户视觉效果会更好,解决方法让展示时和编辑时子标签高度保持一致,保存按钮div使用visibility: hidden来控制显示隐藏;
- 2.当用户偏好很少或者屏幕高度很高时编辑紧跟内容下方,页面出现滚动条时保存按钮悬浮在页面下方;
let customerPreference = document.getElementById('customerPreference')
if ((customerPreference.offsetHeight + 360) > window.innerHeight) { // 360是元素距页面顶部的高度
this.isFixed = true
} else {
this.isFixed = false
}
- 3.保存按钮使用position: fixed定位时按钮块宽度过宽,解决方法采用获取对应正确的元素宽度赋值给按钮块元素;
this.editBoxWidth = this.$refs.edit.clientWidth
- 4.浏览器大小改变时(缩放)的兼容,解决方案是使用window.onresize;
mounted () {
window.onresize = () => {
if (this.$refs.edit) {
this.editBoxWidth = this.$refs.edit.clientWidth
}
}
},
destroyed () {
window.onresize = null // 销毁事件 释放
}
- 5.这个用户偏好的数据是可变的、可配置的,所以会出现多个大类的情况,所以样式使用:nth-child来实现。
实现后的效果图
- 初步完成样式
- 编辑时保存按钮悬浮
- 兼容左侧菜单和内容区padding
整个vue文件代码
<template>
<div class="customerPreference" id="customerPreference">
<template v-if="productsList">
<div class="edit" ref="edit"><el-button type="text" :disabled="isEdit" @click="showEdit"><i class="el-icon-edit">编辑</i></el-button></div>
<div class="large" v-for="itemLarge in productsList" :key="itemLarge.code">
<div class="largeTitle">{{itemLarge.name}}</div>
<div class="largeTitleBorder"></div>
<div class="mediumList">
<template v-if="itemLarge.children">
<div class="mediumLi" v-for="itemMedium in itemLarge.children" :key="itemMedium.code">
<div class="mediumLiTitle">{{itemMedium.name}}</div>
<div class="smallList">
<div v-show="!isEdit" :class="{ smallLiSelect: itemsmall.select, smallLi: true }" v-for="itemsmall in itemMedium.children" :key="`${itemsmall.code}a`">
{{itemsmall.name}}
</div>
<el-checkbox v-show="isEdit" v-model="itemsmall.select" v-for="itemsmall in itemMedium.children" :key="`${itemsmall.code}b`">{{itemsmall.name}}</el-checkbox>
</div>
</div>
</template>
</div>
</div>
<div :class="{ fixedBox: isFixed, buttonBox: true, isVisibility: !isEdit}" :style="`width: ${editBoxWidth + 60}px`">
<el-button @click="cancelEdit">取消</el-button>
<el-button @click="createCstHobby" type="primary">保存</el-button>
</div>
</template>
</div>
</template>
<script>
import { listAllAndCstHobby, createCstHobby } from '@/api/lilingCustomer'
export default {
props: {
cstInfo: {
type: Object
},
cstNo: {
type: String
}
},
watch: {
cstNo () {
if (this.cstNo) {
this.listAllAndCstHobby()
}
}
},
data () {
return {
isFixed: false,
isEdit: false,
editBoxWidth: 0,
productsList: [] // name code children parentCode
}
},
created () {
if (this.cstNo) {
this.listAllAndCstHobby()
}
},
mounted () {
window.onresize = () => {
if (this.$refs.edit) {
this.editBoxWidth = this.$refs.edit.clientWidth
}
}
},
destroyed () {
window.onresize = null // 销毁事件 释放
},
methods: {
listAllAndCstHobby () {
let params = { cstNo: this.cstNo }
listAllAndCstHobby(params).then(res => {
let tree = this.$util.listToTree({
data: res.obj,
parentKey: 'parentCode',
labelKey: 'name',
childrenKey: 'children',
valueKey: 'code',
rootValue: '-1'
})
this.productsList = tree[0].children
})
},
showEdit () {
this.editBoxWidth = this.$refs.edit.clientWidth
this.isEdit = true
this.$nextTick(() => {
this.getBasePayChildrenHeight()
})
},
getBasePayChildrenHeight () { // 获取屏幕高度和元素高度判断是否需要悬浮保存按钮
let customerPreference = document.getElementById('customerPreference')
if ((customerPreference.offsetHeight + 360) > window.innerHeight) { // 360是元素距页面顶部的高度
this.isFixed = true
} else {
this.isFixed = false
}
},
cancelEdit () {
this.isEdit = false
},
createCstHobby () {
let arr = []
let getArray = (data) => {
data.forEach((item, index) => {
if (item.select) {
arr.push(item)
}
if (item.children.length !== 0) {
getArray(item.children)
}
})
}
getArray(this.productsList)
let time = this.$util.formatFullDateTime(new Date())
let list = arr.map((item, index) => {
return {
code: item.code,
parentCode: item.parentCode,
cstNo: this.cstNo,
cstNm: this.cstInfo.cstNm,
effDt: time,
endDt: '2099-12-31 00:00:00'
}
})
createCstHobby({ list: list }).then((res) => {
this.$success('保存成功')
this.listAllAndCstHobby()
this.isEdit = false
})
}
}
}
</script>
<style lang="less" scoped>
.customerPreference{
.el-checkbox{
margin-bottom: 9px;
}
width: 100%;
.edit{
text-align: right;
}
.large{
margin: 12px 0;
padding-bottom: 60px;
.largeTitle{
display: inline-block;
padding: 7px 25px 7px 12px;
line-height: 28px;
background-image: linear-gradient(to right, #FE998C, #F78095);
border-top-left-radius: 4px;
border-top-right-radius: 42px;
}
.largeTitleBorder{
position: relative;
top: -4px;
height: 3px;
opacity: 0.45;
background-image: linear-gradient(to right, #FE998C, #F78095);
}
.mediumList{
display: flex;
justify-content: space-between;
.mediumLi{
flex: 1;
background-color:rgba(218, 144, 154, 0.08);
margin-right: 4px;
padding: 10px 18px;
.mediumLiTitle{
color: #333;
font-size: 14px;
line-height: 20px;
margin-bottom: 16px;
font-weight: 800;
}
}
.mediumLi:last-child{
margin-right: 0;
}
.smallList{
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
.smallLi{
padding: 2px 15px;
line-height: 18px;
font-size: 12px;
color: #3c3b3b;
border: 1px solid #F78294;
border-radius: 11px;
margin: 0 4px 4px 0;
display: none;
background-color: rgba(247, 130, 148, 0.11);
}
.smallLiSelect{
display: block;
}
}
}
}
.buttonBox{
background-color: #fff;
padding: 12px;
display: flex;
justify-content: center;
}
.fixedBox{
z-index: 100;
position: fixed;
bottom: 0px;
left: 212px;
box-shadow: 0 -2px 2px rgba(0,0,0,.1);
}
.isVisibility{
visibility: hidden;
}
.large:nth-child(5n+2) { // 第二项
.largeTitle{
background-image: linear-gradient(to right, #929DF0, #9E6DEB);
}
.largeTitleBorder{
background-image: linear-gradient(to right, #929DF0, #9E6DEB);
}
.mediumList{
.mediumLi{
background-color: rgba(138, 121, 218, 0.07);
}
.smallList{
.smallLi{
border: 1px solid #8A79DA;
background-color: rgba(138, 121, 218, 0.1);
}
}
}
}
.large:nth-child(5n+3) { // 第3项
.largeTitle{
background-image: linear-gradient(to right, #6DA7F2, #3F8CF1);
}
.largeTitleBorder{
background-image: linear-gradient(to right, #6DA7F2, #3F8CF1);
}
.mediumList{
.mediumLi{
background-color: rgba(164, 185, 212, 0.08);
}
.smallList{
.smallLi{
border: 1px solid #418EF2;
background-color: rgba(65, 142, 242, 0.1);
}
}
}
}
.large:nth-child(5n+4) { // 第4项
.largeTitle{
background-image: linear-gradient(to right, #36CFC9, #09C7DB);
}
.largeTitleBorder{
background-image: linear-gradient(to right, #36CFC9, #09C7DB);
}
.mediumList{
.mediumLi{
background-color:rgba(154, 204, 203, 0.08);
}
.smallList{
.smallLi{
border: 1px solid #2DCDCD;
background-color: rgba(11, 199, 219, 0.1);
}
}
}
}
.large:nth-child(5n) { // 第5项
.largeTitle{
background-image: linear-gradient(to right, #4FC8B1, #1BC68D);
}
.largeTitleBorder{
background-image: linear-gradient(to right, #4FC8B1, #1BC68D);
}
.mediumList{
.mediumLi{
background-color:rgba(37, 198, 148, 0.08);
}
.smallList{
.smallLi{
border: 1px solid #25C694;
background-color: rgba(37, 198, 148, 0.1);
}
}
}
}
}
</style>