黑马项目-头条-Mobile-频道编辑操作
2021/6/11 19:02:45
本文主要是介绍黑马项目-头条-Mobile-频道编辑操作,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
频道编辑操作
需求:登录的用户,可以选择喜欢的频道
准备组件布局
目标:实现频道组件基本布局
- 封装独立的组件
组件路径:
src/components/ChannelEdit.vue
<!-- @closed="editing=false" 关闭屉式菜单 重置编辑状态为不编辑 --> <van-action-sheet :value="value" @closed="editing=false" @input="$emit('input', $event)" title="编辑频道"> <div class="channel"> <div class="tit"> 我的频道: <span class="tip">点击可进入频道</span> <van-button v-if="!editing" @click="editing=true" size="mini" type="info" plain>编辑</van-button> <van-button v-else @click="editing=false" size="mini" type="danger" plain>完成</van-button> </div> <van-grid class="van-hairline--left"> <van-grid-item v-for="index in 8" :key="index"> <span class="f12">频道{{index}}</span> <van-icon v-show="editing" class="btn" name="cross"></van-icon> </van-grid-item> </van-grid> </div> <div class="channel"> <div class="tit">可选频道:</div> <van-grid class="van-hairline--left"> <van-grid-item v-for="index in 8" :key="index"> <span class="f12">频道{{index}}</span> <van-icon class="btn" name="plus"></van-icon> </van-grid-item> </van-grid> </div> </van-action-sheet>
props: { value: { type: Boolean, default: false } } data () { return { editing: false } }
- 控制组件的显示
<spanclass="bar_btn"> <van-icon @click='handleEdit' name="wap-nav"></van-icon> </span>
// data中添加数据控制组件弹窗 isEdit: false
<channel-edit v-model="isEdit"></channel-edit>
- 样式处理
.van-popup--bottom{ &.van-popup--round{ border-radius: 0; } } .van-action-sheet { max-height: 100%; height: 100%; .van-action-sheet__header { background: #3296fa; color: #fff; .van-icon-close { color: #fff; } } } .channel { padding: 10px; .tit{ line-height: 3; .tip { font-size: 10px; color: #999; } } .van-button { float: right; margin-top: 7px; } .btn{ position: absolute; bottom: 0; right: 0; background: #ddd; font-size: 12px; color: #fff; } .f12{ font-size:12px; color: #555; } .red{ color: red; } }
总结:
- 控制弹窗的显示和隐藏
- 父子组件的数据传递
- v-model在组件上的用法
渲染我的频道
目标:渲染频道列表数据
- 父组件传递数据给子组件
<!-- 编辑频道组件 --> <channel-edit v-model='showEditChannel' :channels='channels' :activeIndex='active' ></channel-edit>
- 子组件接收父组件数据
props: { value: { type: Boolean, default: false }, channels: { type: Array, default: () => [] }, activeIndex: { type: Number, default: 0 } }, data () { return { // 默认是未编辑状态 editing: false, // 全部频道 channels: [] } },
- 数据动态渲染
<div class="channel"> <div class="tit"> 我的频道: <span class="tip">点击可进入频道</span> <van-button v-if="!editing" @click="editing=true" size="mini" type="info" plain>编辑 </van-button> <van-button v-else size="mini" type="danger" @click="editing=false" plain> 完成 </van-button> </div> <van-grid class="van-hairline--left"> <van-grid-item v-for="(item, i) in channels" :key="item.id"> <span class="f12" :class="{ red: activeIndex===i }"> {{item.name}} </span> <van-icon v-if="editing && i!==0" class="btn" name="cross"> </van-icon> </van-grid-item> </van-grid> </div>
总结:
- 父组件向子组件传值
- 属性的类型检测
- 类的绑定用法
总结
- 更多操作
- 不刚兴趣
- 举报文章
- 父组件将文章的id传递到子组件
- 文章id值如果太大会有问题(js客户处理的数据大小有限)
- 基于json-bigint包实现大值数据的处理
- axios中统一处理后端返回的数据 transformResponse
- 常量数据需要统一维护
- 频道编辑
- 组件的基本布局
- 我的频道数据的动态渲染
- 父子组件之间的数据交互
- v-model在组件标签上的用法
- Vant弹窗组件的用法
反馈
- axios的transformResponse类似于响应拦截器
- 响应拦截器中response参数不仅包含数据,还包括响应头,配置选项等相关信息。
- transformResponse回调参数data表示的特指服务器返回的原始数据,专门用于处理数据。
- axios处理大数
原生js能处理的数值最大值是有限制的,如果一个超出了最大值,那么js就无法准确存储。
可以基于第三方包json-bigint处理大数(本质上就是把大数作为字符串拆分成多端进行存储)
从使用的角度:JSONBig.parse() 类似于JSON.parse() 方法的功能,但是要多出一个功能:对json中的超大数值进行自动处理,转换为一个BigNumber的实例对象(其中包含了一个数组)。该对象在使用的时候需要调用toString()方法转换数值为字符串。
渲染可选频道
目标:渲染可选频道
- 封装接口调用方法
import request from '@/utils/request.js' // 获取所有频道数据 export const getChannels = () => { return request({ method: 'get', url: 'v1_0/channels' }) }
- 组件中调用方法获取全部频道数据
// 弹窗打开时触发 async handleOpen () { // 调用接口获取所有的频道数据 try { const ret = await getChannels() this.allChannels = ret.data.channels } catch { this.$toast('获取所有频道失败') } },
总结:
- 已经拥有【我的频道】和【全部频道】数据
- 基于上述两种频道计算【可选频道】数据
- 弹窗打开时触发加载全部频道的动作(基于Vant组件的事件open)
- 根据 【全部频道】 和 【我的频道】 得到 【可选频道】
- 可选频道 = 全部频道 - 我的频道
computed: { // 计算可选频道的数据 optionChannels () { // 已知所有频道数据 // 当前我的频道数据 return this.allChannels.filter((item) => { // 过滤的条件:item不在我的频道数据中 // arr.some方法作用:判断数组中是否包含符合条件的数据,只要有一项符合,就返回true return !this.channels.some((channel) => { // 让item和我的频道中每一项数据相比 return channel.id === item.id }) }) } // optionChannels () { // // 已知所有频道数据 // // 当前我的频道数据 // const arr = this.allChannels.filter((item) => { // // 过滤的条件:item不在我的频道数据中 // // arr.some方法作用:判断数组中是否包含符合条件的数据,只要有一项符合,就返回true // const ret = this.channels.some((channel) => { // // 让item和我的频道中每一项数据相比 // return channel.id === item.id // }) // return !ret // }) // return arr // } },
- 动态渲染
<div class="channel"> <div class="tit">可选频道:</div> <van-grid class="van-hairline--left"> <van-grid-item v-for="channel in optionalChannels" :key="channel.id"> <span class="f12">{{channel.name}}</span> <van-icon name="plus" class="btn"></van-icon> </van-grid-item> </van-grid> </div>
总结:
- 计算可选频道(算法)
- 动态渲染可选频道数据
点击进入频道
目标:控制点击进入频道
- 事件绑定
<span class="f12" @click="enterChannel(index)"
- 事件函数定义
enterChannel (index) { // 进入频道列表 // 1、关闭窗口 this.$emit('input', false) // 2、修改父组件中频道的索引activeIndex this.$emit('update-index', index) }
- 父组件监听事件
<edit-channel v-model="showEditChannel" :channels="channels" @update-index="active=$event" :activeIndex="active"> </edit-channel>
- 简写方法
- 父子组件之间传值的简化写法
- 父向子传值 :属性名称 (:activeIndex=“active”)
- 子向父传值 @自定义事件名称 (@update-index=“active=$event”)
- 合并的写法
:activeIndex.sync="active"
- 要求:子组件触发事件
- 父子组件之间传值的简化写法
enterChannel (index) { this.$emit('input', false) - this.$emit('update-index', index) + this.$emit('update:activeIndex', index) },
<edit-channel v-model="showEditChannel" :channels="channels" - @update-index="active=$event" - :activeIndex="active"> + :activeIndex.sync="active"> </edit-channel>
总结
- 如果希望传递给子组件的属性是双向绑定的,可以再属性的后面添加.sync即可,但是有一个要求:子组件触发的事件必须是如下的格式 update:属性名称
this.$emit('update:activeIndex', index)
删除我的频道
目标:实现删除我的频道功能
- 封装上传频道接口
// 调用接口删除频道 export const delChannel = async (channelId) => { return request({ method: 'delete', url: 'v1_0/user/channels/' + channelId }) }
- 绑定删除频道事件
<van-icon @click="delChannel(channel.id)"></van-icon>
- 调用接口删除频道
// 删除频道 async handleDelete (id) { try { await delChannel(id) // 通知父组件删除该频道 this.$emit('del-channel', id) } catch { this.$toast('删除频道失败') } },
<channel-edit @del-delete='deleteChannel' v-model='showEditChannel' :channels='channels' :activeIndex.sync='activeIndex' :abc.sync='abc' ></channel-edit>
// 删除频道 delChannel (id) { // 根据id删除对应的频道 const index = this.channels.findIndex(item => { return item.id === id }) this.channels.splice(index, 1) },
总结:
- 封装接口
- 绑定事件调用接口
- 删除频道(子向父组件传值,由父组件根据id删除频道)
添加我的频道接口参数设置
目标:添加我的频道参数处理
添加频道时,需要告诉后端,当前我的频道的顺序,后端不需要【推荐】频道
- 绑定事件,提供(添加频道)数据。
<van-icon name="plus" @click="addChannel(item)" class="btn"></van-icon>
- 接口需要实现 调用后台接口与本地存储功能
- 后台需要排序 [{id:‘频道ID’,seq,‘排序’}]
- 本地需要 {id:‘频道ID’,name:‘频道名称’}
// 因为无法获取后台seq顺号 只能前端排序让后端统一即可。 // 后端需要 完整的排好序的 数组 [{id,seq},...] 注意:不需要推荐 // 本地需要 {id, name} 综合一下:格式如下 // 添加频道 addChannel (channel) { // 准备参数:对每一个频道进行排序(添加一个seq属性进行编号);去掉【推荐】频道 // 先对之前的频道排序 const orderChannels = this.channels.map((item, index) => { return { id: item.id, name: item.name, seq: index } }) // orderChannels = [{id: '',name:'', seq: 0}, {}, {}] // 添加新的频道 orderChannels.push({ id: channel.id, name: channel.name, seq: orderChannels.length }) // 删除最开始的【推荐】频道 orderChannels.splice(0, 1) console.log(orderChannels) },
orderChannels 提供给API使用
总结:
- 频道需要排序(每个频道添加seq属性)
- 提交的数据不可以包含【推荐】频道
添加我的频道
目标:封装添加频道API
- 封装添加频道接口方法
// 添加频道 // 添加频道的接口 export const addChannel = (orderChannels) => { return request({ method: 'put', url: 'v1_0/user/channels', data: { channels: orderChannels } }) }
- 组件实现添加频道功能
- 绑定添加频道的按钮的点击事件
- 封装了添加频道的接口方法
- 准备添加频道调用接口的相关参数
- 要求是数组,数组中放对象,对象中包含频道id和排序序号seq
- seq作用:告诉后端,页面中频道的顺序
- 数组中要去掉【推荐】频道
- 调用接口发送请求
- 如果调用接口成功,在我的频道中添加一个新的频道(点击的添加的频道)
import { addChannel } from '@/api/channel.js' // 添加频道 addChannel (channel) { // 准备参数:对每一个频道进行排序(添加一个seq属性进行编号);去掉【推荐】频道 // 先对之前的频道排序 const orderChannels = this.channels.map((item, index) => { return { id: item.id, name: item.name, seq: index } }) // orderChannels = [{id: '',name:'', seq: 0}, {}, {}] // 添加新的频道 orderChannels.push({ id: channel.id, name: channel.name, seq: orderChannels.length }) // 删除最开始的【推荐】频道 orderChannels.splice(0, 1) // 调用接口实现添加频道 try { // 调用接口成功 addChannel(orderChannels) // 添加频道成功后,添加页码的频道 const newChannel = { // 频道的id id: channel.id, // 频道的标签名称 name: channel.name, // 文章列表加载状态 loading: false, // 下拉刷新的完成状态 isLoading: false, // 上拉列表加载完成的标志 finished: false, // 下拉刷新完成的提示信息 pullText: '加载成功', // 时间戳,用于实现列表的分页查询 timestamp: +new Date(), // 文章列表 articles: [] } // 把新的频道数据传递给父组件,让父组件去添加 this.$emit('add-channel', newChannel) } catch { this.$toast('添加我的频道失败') } },
这篇关于黑马项目-头条-Mobile-频道编辑操作的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南