HarmonyOS鸿蒙Next中购物车页面真机调试,动态删除页面元素后,底部导航栏组件无法点击了
HarmonyOS鸿蒙Next中购物车页面真机调试,动态删除页面元素后,底部导航栏组件无法点击了 按照京东购物车样式写的静态页面。
删除购物车所有商品后,底部导航栏组件无法点击,并且发现日志报错
E 03900/Ace: [<private> (<private>)] the node is not in the map
E 03900/Ace: [<private> (<private>)] Node[1634] can’t be reached.
// cart.js
import prompt from '@system.prompt';
import { setSystemBarProperties } from '../../utils/index';
import cartList from "../../utils/cartList"
export default {
data: {
isEdit: false,
dataLoading: false,
cartList: [],
checkedAll: false,
dialogType: 1, // 1:收藏;2:删除
dialogMessage: ""
},
computed: {
totalCount: {
set() { return 0 },
get() {
return this.cartList.reduce((pre, cur) => {
return pre + cur.sorted.length
}, 0)
}
},
totalPrice: {
set() { return "0.00" },
get() {
if (!this.cartList.length) {
return "0.00"
}
const checkedGoodsList = this.cartList.reduce((pre, cur) => {
const checkedList = cur.sorted.filter(item => item.checked)
return pre.concat(checkedList)
}, [])
const totalPrice = checkedGoodsList.reduce((pre, cur) => {
return pre + ((cur.Price * cur.Num) - cur.Discount)
}, 0)
return totalPrice.toFixed(2)
}
},
discountPrice: {
set() { return "0.00" },
get() {
if (!this.cartList.length) {
return "0.00"
}
const checkedGoodsList = this.cartList.reduce((pre, cur) => {
const checkedList = cur.sorted.filter(item => item.checked)
return pre.concat(checkedList)
}, [])
const discountPrice = checkedGoodsList.reduce((pre, cur) => {
return pre + cur.Discount
}, 0)
return discountPrice.toFixed(2)
}
},
buyTotal: {
set() { return 0 },
get() {
if (!this.cartList.length) {
return 0
}
const checkedGoodsList = this.cartList.reduce((pre, cur) => {
const checkedList = cur.sorted.filter(item => item.checked)
return pre.concat(checkedList)
}, [])
let buyTotal = 0
buyTotal = checkedGoodsList.reduce((pre, cur) => {
return pre + cur.Num
}, 0)
return buyTotal
}
}
},
onInit() {
console.log("cartOnInit");
this.initCartList()
},
onShow() {
this.initBarStatus()
this.initCheckedAll()
},
handleChangeEdit() {
this.isEdit = !this.isEdit
},
initCartList() {
if (this.cartList.length === 0) {
this.dataLoading = true
setTimeout(() => {
cartList.forEach(item => {
item.checked = false
item.sorted.forEach(sItem => {
sItem.checked = false
})
})
this.cartList = cartList
this.initCheckedAll()
this.dataLoading = false
}, 1000)
}
},
initCheckedAll() {
if (this.cartList.length) {
const shopCheckedAll = this.cartList.every(c => c.checked)
this.checkedAll = shopCheckedAll
} else {
this.checkedAll = false
}
},
initBarStatus() {
setSystemBarProperties({
statusBarColor: "#f6f6f6"
})
},
handleShopSelect(item) {
item.checked = !item.checked
item.sorted.forEach(s => {
s.checked = item.checked
})
if (item.checked) {
const shopCheckedAll = this.cartList.every(c => c.checked)
this.checkedAll = shopCheckedAll
} else {
this.checkedAll = false
}
},
handleGoodsSelect(value, shop) {
value.checked = !value.checked
const goodsCheckedAll = shop.sorted.every(s => s.checked)
if (goodsCheckedAll) {
shop.checked = true
const shopCheckedAll = this.cartList.every(c => c.checked)
this.checkedAll = shopCheckedAll
} else {
shop.checked = false
this.checkedAll = false
}
},
handleCheckedAll() {
this.checkedAll = !this.checkedAll
this.cartList.forEach(item => {
item.checked = this.checkedAll
item.sorted.forEach(s => {
s.checked = this.checkedAll
})
})
},
handleGoodsReduce(value) {
if (value.Num > 1) {
value.Num--
}
},
handleGoodsIncrease(value) {
value.Num++
},
toOrder() {
if (!this.buyTotal) {
prompt.showToast({
message: '您还没有选择商品哦',
duration: 1500,
})
return false
}
},
getCheckedCount() {
return this.cartList.reduce((pre, cur) => {
return pre + cur.sorted.filter(s => s.checked).length
}, 0)
},
handleCollect() {
const checkedCount = this.getCheckedCount()
if (!checkedCount) {
prompt.showToast({
message: '您还没有选择商品哦',
duration: 1500,
})
return false
}
this.dialogType = 1
this.dialogMessage = `确定要将这${checkedCount}种商品移入我的收藏?`
this.$element('confirm-dialog').show()
},
handleDelete() {
const checkedCount = this.getCheckedCount()
if (!checkedCount) {
prompt.showToast({
message: '您还没有选择商品哦',
duration: 1500,
})
return false
}
this.dialogType = 2
this.dialogMessage = `确认要删除这${checkedCount}种商品吗?`
this.$element('confirm-dialog').show()
},
handleDilaogConfirm() {
try {
const checkedCount = this.getCheckedCount()
if (checkedCount === this.totalCount) {
this.cartList = []
this.isEdit = false
return false
}
const cartList = []
this.cartList.forEach(item => {
if (!item.checked) {
item.sorted = item.sorted.filter(s => !s.checked)
cartList.push(item)
}
})
this.cartList = cartList
this.handleDialogCancel()
} catch (e) {
console.log(e);
}
},
handleDialogCancel() {
this.$element('confirm-dialog').close()
},
selectService(goods) {
console.log(JSON.stringify(goods));
this.showPanel()
},
showPanel() {
this.$element('simplepanel').show()
},
closePanel() {
this.$element('simplepanel').close()
},
handleClick(message) {
console.log(message);
}
}
// cart.hml
<element name="tabbar" src="../../components/tabbar/tabbar.hml"></element>
<div class="page" style="padding-top: {{ cartList.length > 0 ? '86px' : '40px' }}; padding-bottom: {{ cartList.length > 0 ? '106px' : '56px'}};">
<div class="container">
<div class="header">
<div class="headedr-title">
<text class="header-title-text">购物车</text>
</div>
<div class="header-address">
<image class="address-icon" src="../../common/images/icon_location.png"></image>
<text class="header-address-text">配送至:金水路与燕黑路交叉口西北角兴业大厦10楼1010室</text>
</div>
<div if="{{ cartList.length > 0 }}" class="header-edit-content" onclick="handleChangeEdit">
<text if="{{ ! isEdit }}" class="header-edit-text">编辑</text>
<text if="{{ isEdit }}" class="header-edit-text">完成</text>
</div>
</div>
<div if="{{ cartList.length > 0 }}" class="count-statistc">
<text class="count-total">全部 {{ totalCount }}</text>
</div>
<div if="{{ cartList.length > 0 && ! dataLoading }}" class="cart-conent">
<div for="{{ cartList }}" class="cart-module">
<div class="module-shop-name">
<div class="checkbox-content">
<div class="checkbox-image-content" onclick="handleShopSelect($item)">
<image if="{{ $item.checked }}" class="checkbox-image-item" src="../../common/images/icon_selected.png"></image>
<image if="{{ !$item.checked }}" class="checkbox-image-item" src="../../common/images/icon_unselected.png"></image>
</div>
</div>
<text class="shop-name">{{ $item.shopName }}</text>
<image src="../../common/images/icon_arrow.png" class="jump-icon"></image>
</div>
<div class="goods-list">
<div for="{{ value in $item.sorted }}" class="goods-item">
<div class="checkbox-content">
<div class="checkbox-image-content" onclick="handleGoodsSelect(value, $item)">
<image if="{{ value.checked }}" class="checkbox-image-item" src="../../common/images/icon_selected.png"></image>
<image if="{{ !value.checked }}" class="checkbox-image-item" src="../../common/images/icon_unselected.png"></image>
</div>
</div>
<div class="goods-content">
<div class="goods-image-content">
<image class="goods-image" src="https://img10.360buyimg.com/mobilecms/{{ value.ImageUrlRN }}"></image>
</div>
<div class="goods-info-content">
<div class="goods-name">
<text class="goods-name-text">{{ value.Name }}</text>
</div>
<div class="goods-specification" onclick="selectService(value)">
<text class="goods-specification-text goods-specification-text-ellipse">{{ value.unitedText }}</text>
<text class="goods-specification-text goods-specification-text-service">,选服务</text>
</div>
<div class="goods-show-price">
<text class="goods-show-price-text">¥{{ value.Price }}</text>
<div class="goods-num-content">
<text class="num-option num-reduce {{ value.Num === 1 ? 'num-option-disabled' : '' }}" onclick="handleGoodsReduce(value)">-</text>
<text class="goods-num-text">{{ value.Num }}</text>
<text class="num-option num-increase" onclick="handleGoodsIncrease(value)">+</text>
</div>
</div>
<div class="goods-estimate-price">
<text class="goods-estimate-price-text">预估到手价 ¥{{ ((value.Price * value.Num - value.Discount) / value.Num).toFixed(2) }}</text>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div show="{{ dataLoading }}" class="data-loading">
<image class="loading-gif" src="../../common/images/loaddata.gif"></image>
</div>
<div if="{{ cartList.length === 0 && ! dataLoading }}" class="cart-null">
<image class="cart-null-image" src="../../common/images/5a93c51cN3bb5e37b.png"></image>
<text class="cart-null-message">购物车空空如也,去逛逛吧</text>
</div>
<div if="{{ cartList.length > 0 }}" class="price-statistics">
<div class="price-statistics-left">
<div class="checked-all-content">
<div class="checkbox-content">
<div class="checkbox-image-content" onclick="handleCheckedAll">
<image if="{{ checkedAll }}" class="checkbox-image-item" src="../../common/images/icon_selected.png"></image>
<image if="{{ !checkedAll }}" class="checkbox-image-item" src="../../common/images/icon_unselected.png"></image>
</div>
</div>
<text class="checked-all-text">全选</text>
</div>
<div show="{{ ! isEdit }}" class="price-content">
<text class="total-price-text">合计:¥{{ totalPrice }}</text>
<text class="discount-amount">优惠减:¥{{ discountPrice }}</text>
</div>
</div>
<button if="{{ ! isEdit }}" type="capsule" class="buy-button" onclick="toOrder">去结算({{ buyTotal }})</button>
<div if="{{ isEdit }}" class="edit-button-content">
<button class="edit-button-content-item" onclick="handleCollect">移入收藏</button>
<button class="edit-button-content-item" onclick="handleDelete">删除</button>
</div>
</div>
<tabbar></tabbar>
<dialog id="confirm-dialog">
<div class="dialog-container">
<div class="dialog-message">
<text class="dialog-message-text">{{ dialogMessage }}</text>
</div>
<div class="dialog-button-content">
<button if="{{ dialogType === 1 }}" class="button-item cancel-button" onclick="handleDialogCancel">我再想想</button>
<button if="{{ dialogType === 1 }}" class="button-item confirm-button" onclick="handleDilaogConfirm">移入收藏</button>
<button if="{{ dialogType === 2 }}" class="button-item cancel-button" onclick="handleDialogCancel">取消</button>
<button if="{{ dialogType === 2 }}" class="button-item confirm-button" onclick="handleDilaogConfirm">确定</button>
</div>
</div>
</dialog>
<panel id="simplepanel" type="foldable" mode="half" dragbar="false" miniheight="200px">
<div class="panel-div">
<div class="inner-txt">
<text class="txt">服务选择</text>
</div>
<div class="inner-btn">
<button type="capsule" value="Close" onclick="closePanel"></button>
</div>
</div>
</panel>
</div>
</div>
// cart.css
.page {
width: 100%;
height: 100%;
display: flex;
}
.container {
display: flex;
flex-direction: column;
width: 100%;
min-height: 100%;
background-color: #f6f6f6;
overflow: scroll;
}
.data-loading {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.loading-gif {
width: 100px;
height: 100px;
}
.header {
position: fixed;
left: 0px;
top: 0px;
right: 0px;
padding: 0px 15px;
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 40px;
background-color: #f6f6f6;
}
.headedr-title {
flex-grow: 0;
flex-shrink: 0;
flex-basis: 60px;
display: flex;
justify-content: flex-start;
align-items: center;
}
.headedr-title .header-title-text {
font-size: 18px;
line-height: 18px;
color: #000;
text-align: left;
}
.header-address {
flex-shrink: 1;
flex-grow: 1;
padding: 0px 8px;
display: flex;
align-items: center;
width: 100%;
height: 18px;
background-color: #f0f0f0;
border-radius: 9px;
}
.address-icon {
width: 12px;
height: 12px;
}
.header-address-text {
flex: 1;
flex-grow: 1;
padding-left: 5px;
font-size: 12px;
line-height: 12px;
color: #999;
max-lines: 1;
text-overflow: ellipsis;
}
.header-edit-content {
flex-grow: 0;
flex-shrink: 0;
flex-basis: 40px;
display: flex;
justify-content: flex-end;
align-items: center;
}
.header-edit-content .header-edit-text {
font-size: 14px;
line-height: 14px;
color: #000;
}
.count-statistc {
position: fixed;
left: 0px;
top: 40px;
right: 0px;
padding: 0px 15px;
display: flex;
justify-content: flex-start;
align-items: center;
width: 100%;
height: 46px;
background-color: #f6f6f6;
}
.count-total {
font-size: 16px;
color: #a2353a;
font-weight: bolder;
}
.cart-conent {
padding: 0px 15px;
display: flex;
flex-direction: column;
}
.cart-module {
margin-bottom: 10px;
padding: 0px 10px 20px;
display: flex;
flex-direction: column;
background-color: #ffffff;
border-radius: 15px;
width: 100%;
}
.module-shop-name {
padding: 15px 0px 0px;
display: flex;
align-items: center;
width: 100%;
}
.checkbox-content {
flex-grow: 0;
flex-shrink: 0;
flex-basis: 26px;
width: 26px;
display: flex;
align-items: center;
}
.checkbox-image-content {
width: 26px;
height: 26px;
}
.checkbox-image-item {
width: 26px;
height: 26px;
}
.shop-name {
padding-right: 5px;
font-size: 14px;
line-height: 14px;
font-weight: bolder;
color: #000;
max-lines: 1;
text-overflow: ellipsis;
}
.jump-icon {
flex-grow: 0;
flex-shrink: 0;
flex-basis: 8px;
width: 8px;
height: 8px;
}
.goods-list {
display: flex;
flex-direction: column;
width: 100%;
}
.goods-item {
position: relative;
padding: 10px 0px;
display: flex;
align-items: flex-start;
}
.goods-item .checkbox-content {
position: relative;
top: 31px;
}
.goods-content {
flex-shrink: 1;
flex-grow: 1;
display: flex;
}
.goods-image-content {
flex-grow: 0;
flex-shrink: 0;
flex-basis: 88px;
width: 88px;
height: 88px;
border-radius: 8px;
background-color: #f9f9f9;
}
.goods-image {
width: 88px;
height: 88px;
border-radius: 8px;
background-color: #f9f9f9;
}
.goods-info-content {
flex-grow: 1;
flex-shrink: 1;
display: flex;
flex-direction: column;
padding-left: 12px;
}
.goods-name-text {
font-size: 14px;
line-height: 18px;
color: #000;
max-lines: 2;
text-overflow: ellipsis;
word-break: break-all;
}
.goods-specification {
margin-top: 5px;
display: flex;
flex-wrap: nowrap;
align-items: center;
border-radius: 11px;
}
.goods-specification-text {
padding: 5px 11px;
height: 22px;
font-size: 12px;
line-height: 12px;
color: #575757;
background-color: #f1f1f1;
}
.goods-specification-text-ellipse {
padding-right: 0px;
max-lines: 1;
text-overflow: ellipsis;
border-top-left-radius: 11px;
border-bottom-left-radius: 11px;
word-break: break-all;
}
.goods-specification-text-service {
padding-left: 0px;
flex-shrink: 0;
flex-grow: 0;
border-top-right-radius: 11px;
border-bottom-right-radius: 11px;
}
.goods-show-price {
margin-top: 6px;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
.goods-show-price-text {
font-size: 14px;
color: #000;
font-weight: bolder;
}
.goods-num-content {
display: flex;
border-radius: 13px;
border: 1px solid #d4d4d4;
}
.num-option {
width: 24px;
height: 24px;
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
color: #000;
text-align: center;
}
.num-option-disabled {
color: #d4d4d4;
}
.goods-num-text {
width: 26px;
height: 24px;
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
color: #000;
text-align: center;
border-left: 1px solid #d4d4d4;
border-right: 1px solid #d4d4d4;
}
.goods-estimate-price {
margin-top: 6px;
}
.goods-estimate-price-text {
font-size: 14px;
color: #ba130a;
}
.price-statistics {
position: fixed;
left: 0px;
bottom: 56px;
right: 0px;
padding: 0px 10px;
width: 100%;
height: 50px;
display: flex;
align-items: center;
justify-content: space-between;
background-color: #ffffff;
border-top: 1px solid #dddddd;
}
.price-statistics-left {
display: flex;
align-items: center;
}
.checked-all-content {
display: flex;
align-items: center;
}
.checked-all-text {
font-size: 12px;
color: #000;
}
.price-content {
padding-left: 8px;
display: flex;
flex-direction: column;
}
.total-price-text {
font-size: 14px;
color: #000;
}
.discount-amount {
margin-top: 5px;
font-size: 10px;
color: #727272;
}
.buy-button {
display: flex;
align-items: center;
padding: 0px 18px;
height: 36px;
font-size: 14px;
text-color: #fff;
background-color: #fc3d45;
}
.edit-button-content {
display: flex;
justify-content: flex-end;
align-items: center;
}
.edit-button-content-item {
display: flex;
align-items: center;
margin-left: 14px;
padding: 0px 17px;
height: 34px;
font-size: 14px;
text-color: #000000;
border-radius: 17px;
border: 1px solid #919191;
background-color: #ffffff;
}
#confirm-dialog .dialog-container {
display: flex;
flex-direction: column;
padding: 40px 20px 15px;
width: 295px;
}
#confirm-dialog .dialog-message {
width: 100%;
}
#confirm-dialog .dialog-message .dialog-message-text {
width: 100%;
font-size: 16px;
color: #000;
text-align: center;
}
#confirm-dialog .dialog-button-content {
margin-top: 20px;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
#confirm-dialog .dialog-button-content .button-item {
display: flex;
justify-content: center;
align-items: center;
width: 116px;
height: 28px;
font-size: 14px;
line-height: 14px;
border-radius: 14px;
}
#confirm-dialog .dialog-button-content .cancel-button {
background-color: #ffffff;
text-color: #fe3c45;
border: 1px solid #fe3c45;
}
#confirm-dialog .dialog-button-content .confirm-button {
background-color: #fe3c45;
text-color: #fff;
border: 1px solid #fe3c45;
}
.cart-null {
padding: 70px 0px 65px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
background-color: #ffffff;
}
.cart-null-image {
width: 90px;
height: 90px;
}
.cart-null-message {
margin-top: 15px;
font-size: 16px;
line-height: 16px;
color: #333;
}
// tabbar.hml
<element name="tabbar" src="../../components/tabbar/tabbar.hml"></element>
<toolbar class="toolbarContain" style="position: fixed; bottom: 0px;background-color: #ffffff;">
<toolbar-item
for="{{tabbarList}}"
icon="{{$idx === active ? $item.activeIcon : $item.inactiveIcon}}"
value='{{$item.text}}'
style="color: {{ $idx === active ? '#f2190c' : '#8b8b8b'}}"
onclick="itemClick($item)"
></toolbar-item>
</toolbar>
// tabbar.js
import maRouter from "../../maRouter"
export default {
data: {
active: -1,
tabbarList: [
{
inactiveIcon: "common/images/tabbar/home-normal.png",
activeIcon: "common/images/tabbar/home-active.png",
text: "首页",
path: "pages/index/index"
},
{
inactiveIcon: "common/images/tabbar/category-normal.png",
activeIcon: "common/images/tabbar/category-active.png",
text: "分类",
path: "pages/category/category"
},
{
inactiveIcon: "common/images/tabbar/cart-normal.png",
activeIcon: "common/images/tabbar/cart-active.png",
text: "购物车",
path: "pages/cart/cart"
},
{
inactiveIcon: "common/images/tabbar/my-normal.png",
activeIcon: "common/images/tabbar/my-active.png",
text: "我的",
path: "pages/userCenter/userCenter"
}
]
},
onPageShow() {
const routerState = maRouter.getState()
const index = this.tabbarList.findIndex(item => item.path === (routerState.path + routerState.name))
if (index !== -1) {
this.active = index
}
},
itemClick(item) {
const routerState = maRouter.getState()
const currentRoute = routerState.path + routerState.name
if (currentRoute !== item.path) {
maRouter.push({ url: item.path })
}
}
}
上面是一个页面的代码,下面有整个项目的代码GitHub地址。
操作步骤就是真机打开项目后,在购物车页面右上角编辑,全选购物车商品后,右下角删除,确认后,底部导航栏无法点击。只有点击手机物理返回键才有效果。
项目GitHub地址
更多关于HarmonyOS鸿蒙Next中购物车页面真机调试,动态删除页面元素后,底部导航栏组件无法点击了的实战教程也可以访问 https://www.itying.com/category-93-b0.html
更多关于HarmonyOS鸿蒙Next中购物车页面真机调试,动态删除页面元素后,底部导航栏组件无法点击了的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙Next中,动态删除页面元素后,底部导航栏组件无法点击,可能是由于布局更新未正确触发或事件绑定丢失。建议检查以下几点:
- 布局更新:确保删除元素后,调用
invalidate()
或requestLayout()
方法强制更新布局。 - 事件绑定:确认底部导航栏的事件监听器未被意外移除,重新绑定事件处理函数。
- 焦点问题:检查是否有其他元素获取了焦点,导致导航栏无法响应点击事件。
- 调试日志:通过日志输出,确认删除操作是否影响了导航栏的可见性或交互状态。
如果问题依旧,建议逐步排查代码逻辑,确保删除操作不会影响其他组件的正常功能。