The main functions to be implemented are as follows:

Information list, TAB page switch, article report, channel management, article details, reading memory, focus on function, like function, comment function, reply to comment, search function, login function, personal center, edit information, xiaozhi students…

Today to achieve the main function is: channel add delete function

Channel 1 Management

1.1 Understanding Requirements

On the right side of the channel list, put a button, click this button can pop layer, to pop layer components to display the channel management page

1.2 inviews/home/home.vueAdd button and elastic layer in

<div class='index'> <! -- V-model bidirectional binding: which subscript channels are active --> <van-tabs V-model ="activeIndex">....... </van-tabs> <! <div class="bar-btn" @click="isShowChannelEdit=true"> <van-icon name="wap-nav"/> </div> <! <van-action-sheet v-model="isShowChannelEdit" title=" title "> <p> channel management </p> <p> channel management </p> <p> Channel management </p> </van-action-sheet> </div>Copy the code

Add a variable to data that controls channel editing

data() { return { // .... + isShowChannelEdit: false, // Show channel edit layer}}Copy the code

1.3 Add styles to buttons in Style (Local Styles)

// Channel management switch button. Bar-btn {position: fixed; right: 5px; top: 57px; display: flex; align-items: center; background-color: #fff; Opacity: 0.8; z-index:1; .van-icon-wap-nav{ font-size: 20px; }}Copy the code

1.4 Click the button to test the effect

2 Architecture channel management component

2.1 Because of the complexity of the function, we added a component channelEdit.vue in the home class

<div> </template> <script> export default {name: 'ChannelEdit',} </script>Copy the code

2.2 Introduce components in home.vue to establish parent-child relationship

+ import ChannelEdit from './channelEdit'

components: {
    ArticleList,
    MoreAction,
+   ChannelEdit
  }
Copy the code
<! <ChannelEdit></ChannelEdit> </van-action-sheet>Copy the code

2.3 Test again whether the display content of shell function is: ‘The content of channel management will be placed here’

3 channel management – Component layout

3.1 home/channelEdit.vueAs follows:

<template> <div class="channel-edit"> <! <div class="channel"> <van-cell title=" my channel" :border="false"> <van-button size="mini" Type ="info"> Edit </van-button> </van-cell> <van-grid> <van-grid-item v-for="index in 8" :key="index"> < span > channel {{index}} < / span > < van - icon name = "cross" class = "BTN" > < / van - icon > < / van - the grid - item > < / van - grid > < / div > <! <div class="channel"> <van-cell title=" optional channel" :border="false"></van-cell> <van-grid> <van-grid-item V - for = "index in 8" : the key = "index" > < span > channel {{index}} < / span > < / van - the grid - item > < / van - grid > < / div > < / div > < / template > <script> export default { name: 'ChannelEdit', data () { return { } } } </script> <style lang="less" scoped> .channel{ padding:15px; font-size:14px; } .btn { position: absolute; top: 0; right: 0; font-size: 24px; } </style>Copy the code

3.2 View the layout structure again

3.3 Import my channel information into the structure

Since my channel information was obtained before, we just need to import it from parent to child in home.vue

<! -- https://vant-contrib.gitee.io/vant/#/zh-CN/action-sheet --> <van-action-sheet v-model="showChannelEdit" title=" channel management "> <! -- 1. Father passes son. <channel-edit + :channels="channels"> </channel-edit> </van-action-sheet>Copy the code

In channelEdit. Vue

props: ['channels']
Copy the code
<! <div class="channel"> <van-cell title=" my channel" :border="false"> <van-button size="mini" Type ="info"> Edit </van-button> </van-cell> <van-grid> <van-grid-item v-for="channel in channels" :key="channel. Id "> <span>{{channel.name}}</span> <van-icon name="cross" class="btn"></van-icon> </van-grid-item> </van-grid> </div>Copy the code

3.3 View my channel rendering effect

3.4 Render of optional channels

3.4.1 track analysis

  1. Content of optional channels: All channels retrieved – the channels selected by the user

  2. To dynamically detect content changes => Recalculation is required when users are added or deleted

3.4.2 To obtain all channel contents, a new interface needs to be called

Continue to encapsulate it inapi/channel.jsAdd an interface to the

/ / export const getAllChannels = () => {return request({method: 'GET', url: 'v1_0/channels'})}Copy the code

3.4.3 Load the call in the child component channelEdit.vue

All obtained channel contents are stored in allChannels array for convenient subtraction later

<script>
import { getAllChannels } from '@/api/channel.js'
export default {
  name: 'ChannelEdit',
  props: ['channels'],
  data () {
    return {
      allChannels: []
    }
  },
  created () {
    this.loadAllChannels()
  },
  methods: {
    async loadAllChannels () {
      const res = await getAllChannels()
      this.allChannels = res.data.data.channels
    }
  }
}
</script>
Copy the code

3.4.4 Write code in computed property computed

// Generate new data based on existing data ---- Computed properties computed: { recommendChannels () { const arr = this.allChannels.filter(channel => { const idx = this.channels.findIndex(item => item.id === channel.id) if (idx === -1) { return true } }) return arr // return this.allChannels - this.channels } }Copy the code

It can also be reduced to a single line of code:

return this.allChannels.filter((item) => ! this.channels.some(index => index.id === item.id))Copy the code

3.4.5 Render subtracted data to the page

<! <div class="channel"> <van-cell title=" optional channel" :border="false"></van-cell> <van-grid> <van-grid-item v-for="channel in recommendChannels" :key="channel.id"> <span>{{channel.name}}</span> </van-grid-item> </van-grid> </div>Copy the code

3.4.6 Checking whether the Function is implemented

We found that there was still duplicate content. When we opened the vue debugging tool, we found that the ID value in my channel was in string format and we used congruence when judging, which was the key cause of the problem. There are two solutions

  1. Change === to == (here because MY Eslint doesn’t allow us to use ==)

  2. Change the route location to Number(item.id) and convert

Double check (already ok)

4 Realize the channel jump by clicking

4.1 Realize click channel hopping

Add a custom event listener for change-channel to the parent component home.vue

<! -- https://vant-contrib.gitee.io/vant/#/zh-CN/action-sheet --> <van-action-sheet v-model="showChannelEdit" title=" channel management "> <! -- 1. Father passes son. <channel-edit :channels="channels" + @change-channel="hChangeChannel" ></channel-edit> </van-action-sheet>Copy the code

Add a callback

HChangeChannel (curIdx) {console.log(' Parent component received my channel clicked in child component ', curIdx) // 1. This. active = curIdx // 2. Turn off this. IsShowChannelEdit = false},Copy the code

4.2 Sub-component channelEdit component

<! <div class="channel"> <van-cell title=" my channel" :border="false"> <van-button size="mini" Type ="info"> edit </van-button> </van-cell> <van-grid> <van-grid-item + v-for="(channel, idx) in channels" :key="channel.id" + @click="hClickMyChannel(idx)" > <span>{{channel.name}}</span> <! -- <van-icon name="cross" class="btn" ></van-icon> --> </van-grid-item> </van-grid> </div>Copy the code
HClickMyChannel (idx) {this.$emit('change-channel', idx)};Copy the code

4.3 Highlight the current channel after entering the channel

 <channel-edit
+       :curIndex="active"
        @change-channel="hChangeChannel"
        :channels="channels"
      ></channel-edit>
    </van-action-sheet>
Copy the code

In the child component:

Props: ['channels', // current channels + 'curIndex' // index of the currently selected channel],Copy the code
<van-grid-item v-for="(channel,idx) in channels" ...... + :class="{red:idx===curIndex}" > <span>{{channel.name}}</span> <! -- <van-icon name="cross" class="btn"></van-icon> --> </van-grid-item> </van-grid>Copy the code

Add style to class name

<van-cell title=" mY channel ":border="false"> + <van-button class="bg" size="mini" type="info"> Edit </van-button> </van-cell> // Highlight. Red {color: red; font-weight: bold; } .bg { background-color: #fff; color: red; border-color: red; }Copy the code

View the effect:

5 Add my channel

5.1 Click optional Channels to add to my channel

insrc/api/channels.jsAdd method to

Return request({url: '/v1_0/user/channels', // method: 'PATCH', data: { channels } }) }Copy the code

5.2 Register click events for channels in recommended channels

<! <div class="channel"> <van-cell title=" optional channel" :border="false" ></van-cell> <van-grid> <van-grid-item  v-for="channel in recommendChannels" :key="channel.id" + @click="hAddChannel(channel)" > <span>{{channel.name}}</span> </van-grid-item> </van-grid> </div>Copy the code

5.3 Complete core functions

Async hAddChannel (channel) {try {// 1. Const res = await addChannels([channel]) // 2. Console. log(res)} catch (err) {console.log(err) this.$toast.fail(' failed to add channel ')}},Copy the code

5.4 Add My Channels – Complete the update on the view

Add the code in the previous update view

this.channels.push(channel)
Copy the code

Channel 6 management – Delete my channel

Requirements: users click “edit”, in my channel, display X, and then click X, you can delete the designated channel.

6.1 Add isEditing data item to realize view interaction

Add to the child component

Data () {return {+ editing: false, // allChannels: [] // allChannels}}Copy the code

Modify the view

<div class="channel"> <van-cell title=" my channel" :border="false" > <van-button size="mini" class="editBtn" + @click="isEditing=! isEditing" + >{{isEditing ? "Cancel", "edit"}} < / van - button > < / van - cell > < van - grid > <! If the current index is the same as the curIndex passed in, add a new class: red --> <! -- :class="{class name: bool}" --> <van-grid-item v-for="(channel, idx) in channels" :key="channel.id" :class="{red: idx===curIndex}" @click="hClickMyChannel(idx)" > <span>{{channel.name}}</span> + <! -- Only if: editing is true and not recommended, show X --> <van-icon + v-show=" editing &&idx! ==0" name="cross" class="btn" ></van-icon> </van-grid-item> </van-grid> </div>Copy the code

6.2 Implement delete my channel

Add an interface to SRC \ API \channel.js:

@param {*} channelId Id of the channel to be deleted * @returns */ export const delChannel = (channelId) => {return request({} url: '/v1_0/user/channels/' + channelId, method: 'DELETE' }) }Copy the code

6.3 Adding Event processing

Import {getAllChannels, addChannel, delChannel} from '@/ API /channel.js' Normal condition: after clicking, do channel jump // 2. And when I did, HClickMyChannel (idx) {if (this.editing) {this.dodeletechannel (idx)} else { this.$emit('change-channel', idx) } }, async doDeleteChannel (idx) { // 1. Const channelId = this.channels[idx].channel Do delete try {await delChannel(channelId) // my channel less 1 item, This.channels.splice (idx, 1) this.$toasters. Success (' delete successful ')} Catch (err) {console.log(err)}},Copy the code

6.4 fix the BUG

6.4.1

inchannelEdit.vueIn the

async doDeleteChannel (idx) { // 1. Const id = this.channels[idx].id console.log(' You want to delete channel ID is ', id) // 2. Try {const res = await delChannel(id) console.log(res) this.$toast.success(' Delete channel succeeded ') // If you delete channel before current channel, Active + if (idx < this.curindex) {+ this.$emit('fixed-active-index') +} // 3. This.channels.splice (idx, 1)} Catch (err) {console.log(err) this.$toasters. Fail (' Delete channel failed ')}},Copy the code

In the home. In vue

<channel-edit
        :curIndex="active"
        @change-channel="hChangeChannel"
+        @fixed-active-index="hFixedActiveIndex"
        :channels="channels"
      ></channel-edit>
Copy the code

supplement

Active -1 hFixedActiveIndex () {this.active--},Copy the code

6.4.2 Edit channel closed open or edit state

inhome.vueAdd the following code to:

<! + <div class="bar-btn" @click="openChannelList"> <van-icon name="wap-nav" /> </div> <! <van-action-sheet v-model="isShowChannelEdit" title=" title "> <! - note: Because the component's outer layer contains a van-action-sheet that is not created after the page is opened or refreshed, <channelEdit :channels="channels" + ref="channelEdit" @change-channel="hchangeChannel" :curIdx="active" @update-active="hUpdateActive" ></channelEdit> </van-action-sheet>Copy the code

Supplement methods to methods:

openChannelList () {
      this.isShowChannelEdit = true
      if (this.$refs.channelEdit) { this.$refs.channelEdit.isEditing = false }
    },
Copy the code

6.4.3 Deleting the recommended problems by editing the status

inchannelEdit.vueAdd the following code to the

Async doDeleteChannel (index) {const id = this.channels[index].id try {await delChannels(id)} catch (err) If (index < this.curIdx) {this.$emit('update-active')}  + if (index ! == 0) {+ // Delete the current item from channels $channels. Splice (index, 1) + this.channels.splice(index, 1) + this.$toast.success(' delete successful ')}},Copy the code