网站推广智选刺盾云下拉,老鹰网营销型网站建设,做兼职一般去哪个网站,企业如何创建网站提示#xff1a;文章写完后#xff0c;目录可以自动生成#xff0c;如何生成可参考右边的帮助文档 文章目录 9.2 收货地址区域9.2.1 创建收货地址组件9.2.2 实现收货地址区域的按需展示9.2.3 实现选择收货地址的功能9.2.4 将 address 信息存储到 vuex 中9.2.5 将 Store 中的… 提示文章写完后目录可以自动生成如何生成可参考右边的帮助文档 文章目录 9.2 收货地址区域9.2.1 创建收货地址组件9.2.2 实现收货地址区域的按需展示9.2.3 实现选择收货地址的功能9.2.4 将 address 信息存储到 vuex 中9.2.5 将 Store 中的 address 持久化存储到本地9.2.6 将 addstr 抽离为 getters9.2.7 重新选择收货地址9.2.8 解决收货地址授权失败的问题9.2.9 解决 iPhone 真机上无法重新授权的问题 9.3 结算区域9.3.1 把结算区域封装为组件9.3.2 渲染结算区域的结构和样式9.3.3已勾选商品的总数量9.3.4 动态渲染全选按钮的选中状态9.3.5 实现商品的全选/反选功能9.3.6 动态渲染已勾选商品的总价格9.3.7 动态计算购物车徽标的数值9.3.8 渲染购物车为空时的页面结构9.4 分支的合并与提交 9.2 收货地址区域
9.2.1 创建收货地址组件
在 components 目录上鼠标右键选择 新建组件并填写组件相关的信息渲染收货地址组件的基本结构
view!-- 选择收货地址的盒子 --view classaddress-choose-boxbutton typeprimary sizemini classbtnChooseAddress请选择收货地址/button/view!-- 渲染收货信息的盒子 --view classaddress-info-boxview classrow1view classrow1-leftview classusername收货人textescook/text/view/viewview classrow1-rightview classphone电话text138XXXX5555/text/viewuni-icons typearrowright size16/uni-icons/view/viewview classrow2view classrow2-left收货地址/viewview classrow2-right河北省邯郸市肥乡区xxx 河北省邯郸市肥乡区xxx 河北省邯郸市肥乡区xxx 河北省邯郸市肥乡区xxx /view/view/view!-- 底部的边框线 --image src/static/cart_border2x.png classaddress-border/image
/view添加样式
// 底部边框线的样式
.address-border {display: block;width: 100%;height: 5px;
}// 选择收货地址的盒子
.address-choose-box {height: 90px;display: flex;align-items: center;justify-content: center;
}// 渲染收货信息的盒子
.address-info-box {font-size: 12px;height: 90px;display: flex;flex-direction: column;justify-content: center;padding: 0 5px;// 第一行.row1 {display: flex;justify-content: space-between;.row1-right {display: flex;align-items: center;.phone {margin-right: 5px;}}}// 第二行.row2 {display: flex;align-items: center;margin-top: 10px;.row2-left {white-space: nowrap;}}
}9.2.2 实现收货地址区域的按需展示
在 data 中定义收货地址的信息对象
export default{data(){address:[] }
}使用 v-if 和 v-else 实现按需展示
!-- 选择收货地址的盒子 --
view classaddress-choose-box v-ifJSON.stringify(address) {}button typeprimary sizemini classbtnChooseAddress请选择收货地址/button
/view!-- 渲染收货信息的盒子 --
view classaddress-info-box v-else!-- 省略其它代码 --
/view9.2.3 实现选择收货地址的功能
为 请选择收货地址 的 button 按钮绑定点击事件处理函数
!-- 选择收货地址的盒子 --
view classaddress-choose-box v-ifJSON.stringify(address) {}button typeprimary sizemini classbtnChooseAddress clickchooseAddress请选择收货地址/button
/view定义 chooseAddress 事件处理函数调用小程序提供的 chooseAddress() API 实现选择收货地址的功能
methods: {// 选择收货地址async chooseAddress() {// 1. 调用小程序提供的 chooseAddress() 方法即可使用选择收货地址的功能// 返回值是一个promise第 1 项为错误对象第 2 项为成功之后的对象const [err, succ] await uni.chooseAddress().catch(err err)// 2. 用户成功的选择了收货地址if (err null succ.errMsg chooseAddress:ok) {// 为 data 里面的收货地址对象赋值this.address succ}}
}定义收货详细地址的计算属性
computed: {// 收货详细地址的计算属性addstr() {if (!this.address.provinceName) return // 拼接 省市区详细地址 的字符串并返回给用户return this.address.provinceName this.address.cityName this.address.countyName this.address.detailInfo}
}渲染收货地址区域的数据
!-- 渲染收货信息的盒子 --
view classaddress-info-box v-elseview classrow1view classrow1-leftview classusername收货人text{{address.userName}}/text/view/viewview classrow1-rightview classphone电话text{{address.telNumber}}/text/viewuni-icons typearrowright size16/uni-icons/view/viewview classrow2view classrow2-left收货地址/viewview classrow2-right{{addstr}}/view/view
/view9.2.4 将 address 信息存储到 vuex 中
在 store 目录中创建用户相关的 vuex 模块命名为 user.js
export default {// 开启命名空间namespaced: true,// state 数据state: () ({// 收货地址address: {},}),// 方法mutations: {// 更新收货地址updateAddress(state, address) {state.address address},},// 数据包装器getters: {},
}在 store/store.js 模块中导入并挂载 user.js 模块
// 1. 导入 Vue 和 Vuex
import Vue from vue
import Vuex from vuex
// 导入购物车的 vuex 模块
import moduleCart from ./cart.js
// 导入用户的 vuex 模块
import moduleUser from ./user.js// 2. 将 Vuex 安装为 Vue 的插件
Vue.use(Vuex)// 3. 创建 Store 的实例对象
const store new Vuex.Store({// TODO挂载 store 模块modules: {// 挂载购物车的 vuex 模块模块内成员的访问路径被调整为 m_cart例如// 购物车模块中 cart 数组的访问路径是 m_cart/cartm_cart: moduleCart,// 挂载用户的 vuex 模块访问路径为 m_userm_user: moduleUser,},
})// 4. 向外共享 Store 的实例对象
export default store改造 my-address.vue 组件中的代码使用 vuex 提供的 address 计算属性 替代 data 中定义的本地 address 对象
// 1. 按需导入 mapState 和 mapMutations 这两个辅助函数
import { mapState, mapMutations } from vuex
export default{name:my-address,data(){// 2.1 注释掉下面的 address 对象使用 2.2 中的代码替代之// address: {}},methods:{// 3.1 把 m_user 模块中的 updateAddress 函数映射到当前组件...mapMutations(m_user,[updateAddress]),//选择收货地址async chooseAddress(){// 1.调用小程序提供的 chooseAddress() 方法即可使用选择收货地址的功能//2.返回值是一个数组第 1 项为错误对象第 2 项为成功之后的收货地址对象const [err,succ] await uni.chooseAddress().catch(errerr)}//2.用户成功的选择了收货地址if(err null succ.errMsg chooseAddress:ok){// 3.2 把下面这行代码注释掉使用 3.3 中的代码替代之// this.address succ // 3.3 调用 Store 中提供的 updateAddress 方法将 address 保存到 Store 里面this.updateAddress(succ)}},computed:{// 2.2 把 m_user 模块中的 address 对象映射当前组件中使用代替 data 中 address 对象...mapState(m_user, [address]),// 将 m_user 模块中的 addstr 映射到当前组件中使用...mapGetters(m_user,[addstr]),// 收货详细地址的计算属性addStr(){if(!this.address.provinceName) return return this.address.provinceName this.address.cityName this.address.countyName this.address.detailInfo}
}9.2.5 将 Store 中的 address 持久化存储到本地
修改 store/user.js 模块中的代码
//更新收货地址updateAddress(state,address){state.address address// 2. 通过 this.commit() 方法调用 m_user 模块下的 saveAddressToStorage 方法将 address 对象持久化存储到本地this.commit(m_user/saveAddressToStorage)},// 1. 定义将 address 持久化存储到本地 mutations 方法saveAddressToStorage(state){uni.setStorageSync(address,JSON.stringify(state.address))}9.2.6 将 addstr 抽离为 getters
为了提高代码的复用性可以把收货的详细地址抽离为 getters方便在多个页面和组件之间实现复用剪切 my-address.vue 组件中的 addstr 计算属性的代码粘贴到 user.js 模块中作为一个 getters 节点
//数据包装器getters:{//收货详细地址的计算属性addstr(state){if(!state.address.provinceName) return //拼接省、市、区、详细地址的字符串并返回给用户return state.address.provinceName state.address.cityName state.address.countyName state.address.detailInfo}}改造 my-address.vue 组件中的代码通过 mapGetters 辅助函数将 m_user 模块中的 addstr 映射到当前组件中使用
// 按需导入 mapGetters 辅助函数
import { mapState, mapMutations, mapGetters } from vuex
export default {// 省略其它代码computed: {...mapState(m_user, [address]),// 将 m_user 模块中的 addstr 映射到当前组件中使用...mapGetters(m_user, [addstr]),},
}9.2.7 重新选择收货地址
为 class 类名为 address-info-box 的盒子绑定 click 事件处理函数如下
!-- 渲染收货信息的盒子 --
view classaddress-info-box v-else clickchooseAddress!-- 省略其它代码 --
/view9.2.8 解决收货地址授权失败的问题
如果在选择收货地址的时候用户点击了取消授权则需要进行特殊的处理否则用户将无法再次选择收货地址改造 chooseAddress 方法
// 选择收货地址
async chooseAddress() {// 1. 调用小程序提供的 chooseAddress() 方法即可使用选择收货地址的功能// 返回值是一个数组第1项为错误对象第2项为成功之后的收货地址对象const [err, succ] await uni.chooseAddress().catch(err err)// 2. 用户成功的选择了收货地址if (succ succ.errMsg chooseAddress:ok) {// 更新 vuex 中的收货地址this.updateAddress(succ)}// 3. 用户没有授权if (err err.errMsg chooseAddress:fail auth deny) {this.reAuth() // 调用 this.reAuth() 方法向用户重新发起授权申请}
}在 methods 节点中声明 reAuth 方法
methods:{// 3.1 把 m_user 模块中的 updateAddress 函数映射到当前组件...mapMutations(m_user,[updateAddress]),// 调用此方法重新发起收货地址的授权async reAuth(){// 3.1 提示用户对地址进行授权const [err2,confirmResult] await uni.showModal({content:检测到您没打开地址权限是否去设置打开,confirmText:确认,cancelText:取消,})// 3.2 如果弹框异常则直接退出if(err2) return// 3.3 如果用户点击了 “取消” 按钮则提示用户 “您取消了地址授权”if(confirmResult.cancel) return uni.$showMsg(您取消了地址授权)// 3.4 如果用户点击了 “确认” 按钮则调用 uni.openSetting() 方法进入授权页面让用户重新进行授权if(confirmResult.confirm) return uni.openSetting({// 3.4.1 授权结束需要对授权的结果做进一步判断success:(settingResult){// 3.4.2 地址授权的值等于 true提示用户 “授权成功”if(settingResult.authSetting[scope.address)return uni.$showMsg(授权成功请选择地址)// 3.4.3 地址授权的值等于 false提示用户 “您取消了地址授权” if(!settingResult.authSetting[scope.address)return uni.$showMsg(您取消了地址授权) }})}
}9.2.9 解决 iPhone 真机上无法重新授权的问题
–问题说明在 iPhone 设备上当用户取消授权之后再次点击选择收货地址按钮的时候无法弹出授权的提示框
导致问题的原因 - 用户取消授权后再次点击 “选择收货地址” 按钮的时候在模拟器和安卓真机上错误消息 err.errMsg 的值为 chooseAddress:fail auth deny在 iPhone 真机上错误消息 err.errMsg 的值为 chooseAddress:fail authorize no response –解决问题的方案 - 修改 chooseAddress 方法中的代码进一步完善用户没有授权时的 if 判断条件
async chooseAddress(){
if (err (err.errMsg chooseAddress:fail auth deny || err.errMsg chooseAddress:fail authorize no response)) {this.reAuth() //调用 this.reAuth() 方法向用户重新发起授权申请}
}9.3 结算区域
9.3.1 把结算区域封装为组件
在 components 目录中新建 my-settle 结算组件初始化 my-settle 组件的基本结构和样式
template!-- 最外层的容器 --view classmy-settle-container结算组件/view
/templatescript
export default {data() {return {}},
}
/scriptstyle langscss
.my-settle-container {/* 底部固定定位 */position: fixed;bottom: 0;left: 0;/* 设置宽高和背景色 */width: 100%;height: 50px;background-color: cyan;
}
/style在 cart.vue 页面中使用自定义的 my-settle 组件并美化页面样式防止页面底部被覆盖
templateview classcart-container!-- 使用自定义的 address 组件 --!-- 购物车商品列表的标题区域 --!-- 商品列表区域 --!-- 结算区域 --my-settle/my-settle/view
/templatestyle langscss
.cart-container {padding-bottom: 50px;
}
/style9.3.2 渲染结算区域的结构和样式
定义如下的 UI 结构
!-- 最外层的容器 --
view classmy-settle-container!-- 全选区域 --label classradioradio color#C00000 :checkedtrue /text全选/text/label!-- 合计区域 --view classamount-box合计:text classamount1234.00/text/view!-- 结算按钮 --view classbtn-settle结算(0)/view
/view样式
.my-settle-container {position: fixed;bottom: 0;left: 0;width: 100%;height: 50px;// 将背景色从 cyan 改为 whitebackground-color: white;display: flex;justify-content: space-between;align-items: center;padding-left: 5px;font-size: 14px;.radio {display: flex;align-items: center;}.amount {color: #c00000;}.btn-settle {height: 50px;min-width: 100px;background-color: #c00000;color: white;line-height: 50px;text-align: center;padding: 0 10px;}
}9.3.3已勾选商品的总数量
在 store/cart.js 模块中定义一个名称为 checkedCount 的 getters用来统计已勾选商品的总数量
// 勾选的商品的总数量
checkedCount(state) {// 先使用 filter 方法从购物车中过滤器已勾选的商品// 再使用 reduce 方法将已勾选的商品总数量进行累加// reduce() 的返回值就是已勾选的商品的总数量return state.cart.filter(x x.goods_state).reduce((total, item) total item.goods_count, 0)
}在 my-settle 组件中通过 mapGetters 辅助函数将需要的 getters 映射到当前组件中使用
import { mapGetters } from vuex
export default {computed: {...mapGetters(m_cart, [checkedCount]),},data() {return {}},
}将 checkedCount 的值渲染到页面中
!-- 结算按钮 --
view classbtn-settle结算({{checkedCount}})/view9.3.4 动态渲染全选按钮的选中状态
使用 mapGetters 辅助函数将商品的总数量映射到当前组件中使用并定义一个叫做 isFullCheck 的计算属性
import { mapGetters } from vuex
export default {computed: {// 1. 将 total 映射到当前组件中...mapGetters(m_cart, [checkedCount, total]),// 2. 是否全选isFullCheck() {return this.total this.checkedCount }}
}为 radio 组件动态绑定 checked 属性的值
!-- 全选区域 --
label classradioradio color#C00000 :checkedisFullCheck /text全选/text
/label9.3.5 实现商品的全选/反选功能
在 store/cart.js 模块中定义一个叫做 updateAllGoodsState 的 mutations 方法用来修改所有商品的勾选状态
// 更新所有商品的勾选状态
updateAllGoodsState(state, newState) {// 循环更新购物车中每件商品的勾选状态state.cart.forEach(xx.goods_state newState)// 持久化存储到本地this.commit(m_cart/saveToStorage)
}在 my-settle 组件中通过 mapMutations 辅助函数将需要的 mutations 方法映射到当前组件中使用
// 1. 按需导入 mapMutations 辅助函数
import { mapGetters, mapMutations } from vuex
export default{methods:{// 2. 使用 mapMutations 辅助函数把 m_cart 模块提供的 updateAllGoodsState 方法映射到当前组件中使用...mapMutations(m_cart,[updateAllGoodsState])}
}为 UI 中的 label 组件绑定 click 事件处理函数
!-- 全选区域 --
label classradio clickchangeAllStateradio color#C00000 :checkedisFullCheck /text全选/text
/label在 my-settle 组件的 methods 节点中声明 changeAllState 事件处理函数
methods:{
// label 的点击事件处理函数changeAllState(){// 修改购物车中所有商品的选中状态// !this.isFullCheck 表示当前全选按钮的状态取反之后就是最新的勾选状态this.updateAllGoodsState(!this.isFullCheck)}
}9.3.6 动态渲染已勾选商品的总价格
在 store/cart.js 模块中定义一个叫做 checkedGoodsAmount 的 getters用来统计已勾选商品的总价格
// 已勾选的商品的总价
checkedGoodsAmount(state) {return state.cart.filter(xx.goods_state).reduce((total,item)total item.goods_count * item.goods_price,0).toFixed(2)
}在 my-settle 组件中使用 mapGetters 辅助函数把需要的 checkedGoodsAmount 映射到当前组件中使用
...mapGetters(m_cart,[checkedCount,total,checkedGoodsAmount]),
在组件的 UI 结构中渲染已勾选的商品的总价
!-- 合计区域 --
view classamount-box合计:text classamount{{checkedGoodsAmount}}/text
/view9.3.7 动态计算购物车徽标的数值
当修改购物车中商品的数量之后tabBar 上的数字徽标不会自动更新。改造 mixins/tabbar-badge.js 中的代码使用 watch 侦听器监听 total 总数量的变化从而动态为 tabBar 的徽标赋值
watch:{//监听totaltotal(){//调用methods中的setBadge方法重新为tabBar的数字徽章赋值this.setBadge() }
}9.3.8 渲染购物车为空时的页面结构
改造 cart.vue 页面的 UI 结构使用 v-if 和 v-else 控制购物车区域和空白购物车区域的按需展示
!-- 收货地址组件 --view classcart-container v-ifcart.length !0...其他代码/view
!-- 空白情况 --view classempty-cart v-elsetext classtip-text购物车没有物品请添加物品/text/view9.4 分支的合并与提交
将 cart 分支进行本地提交(git add .)(git commit -m ‘文本信息’)将本地cart分支提交远端(git push -u origin cart)将本地cart分支合并到master推送到远端(git checkout master)(git merge cart)(git push)删除本地cart分支(git branch -d cart)