Home page - article list

Posted by ryans18 on Thu, 10 Mar 2022 15:08:00 +0100

Home page - article list

# 1. Page layout

# 1.1 head navigation bar

1. Using the navigation bar component

2. Insert button in navigation bar component

  • text
  • Icon

3. Style adjustment

  • Width and height
  • Background color
  • frame
  • Text size
  • Icon size
<template>
  <div class="home-container">
    <!-- navigation bar -->
    <van-nav-bar class="page-nav-bar" fixed>
      <van-button
        class="search-btn"
        slot="title"
        type="info"
        size="small"
        round
        icon="search"
      >search</van-button>
    </van-nav-bar>
    <!-- /navigation bar -->
  </div>
</template>

<script>
export default {
  name: 'HomeIndex',
  components: {},
  props: {},
  data () {
    return {}
  },
  computed: {},
  watch: {},
  created () {},
  mounted () {},
  methods: {}
}
</script>

<style scoped lang="less">
.home-container {
  /deep/ .van-nav-bar__title {
    max-width: unset;
  }
  .search-btn {
    width: 555px;
    height: 64px;
    background-color: #5babfb;
    border: none;
    font-size: 28px;
    .van-icon {
      font-size: 32px;
    }
  }
}
</style>

# 2. Channel list

# 2.1. Use Tab tab component

reference resources: Tab tab component (opens new window)

# 2.2 style adjustment

(1) Basic style adjustment

  • Label item
    • border-right
    • bottom
    • Width and height
    • Text size
    • Text color
  • Bottom bar
    • Width and height
    • colour
    • position

(2) Handle hamburger button

1. Insert content using slots

2. Style adjustment

  • location
  • Content centered
  • Width and height
  • Background color, transparency
  • Font icon size

3. Set gradient borders with pseudo elements

  • location
  • Width and height
  • Background map
  • Background fill mode

4. Add placeholders to act as content areas

HTML structure

<!-- Channel list -->
<!--
animated Sliding animation
border Bottom border line
swipeable Turn on left and right gesture sliding
-->
<van-tabs  class="channel-tabs" v-model="active" swipeable animated border>
    <van-tab title="Label 1">Content 1 content 1 content 1 content 1 content 1 content 1 content 1 content 1 content 1 content 1 content 1</van-tab>
    <van-tab title="Label 2">Content 2 content 1 content 1 content 1 content 1 content 1 content 1 content 1</van-tab>
    <van-tab title="Label 3">Content 3 content 1 content 1 content 1 content 1 content 1</van-tab>
    <van-tab title="Label 4">Content 4</van-tab>
    <van-tab title="Label 6">Content 6</van-tab>
    <van-tab title="Label 7">Content 7</van-tab>
    <van-tab title="Label 8">Content 8</van-tab>
    <!-- Custom content on the right -->
    <!-- Occupying element -->
    <div class="placeholder"></div>
    <!-- Right button -->
    <template #nav-right>
      <div class="hamburger-btn">
        <i class="toutiao toutiao-gengduo"></i>
      </div>
    </template>
</van-tabs>
<!-- /Channel list -->

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

CSS Style:

  /deep/ .channel-tabs {
    .van-tab {
      border-right: 1px solid #edeff3;
      min-width: 200px;
      font-size: 30px;
      color: #777777;
    }

    .van-tab--active {
      color: #333333;
    }

    .van-tabs__nav {
      padding-bottom: 0;
    }

    .van-tabs__line {
      bottom: 8px;
      width: 31px !important;
      height: 6px;
      background-color: #3296fa;
    }

    .placeholder {
      flex-shrink: 0;
      width: 66px;
      height: 82px;
    }

    .hamburger-btn {
      position: fixed;
      right: 0;
      display: flex;
      justify-content: center;
      align-items: center;
      width: 66px;
      height: 82px;
      background-color: #fff;
      background-color: rgba(255, 255, 255, 0.902);
      i.toutiao {
        font-size: 33px;
      }
      &:before {
        content: "";
        position: absolute;
        left: 0;
        width: 1px;
        height: 58px;
        background-image: url(~@/assets/gradient-gray-line.png);
        background-size: contain;
      }
    }
  }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

Note: depth selector https://vue-loader.vuejs.org/zh/guide/scoped-css.html#%E6%B7%B1%E5%BA%A6%E4%BD%9C%E7%94%A8%E9%80%89%E6%8B%A9%E5%99%A8

# 2.3 display channel list

Idea:

  • Step 1: File encapsulation request method under api directory
  • Step 2: define variables in data to store data
  • Step 3: define the data acquisition method in methods
  • 3.1 import this method into the page
  • 3.2 calling methods to send requests in the methods method
  • 3.3 request error handling
  • 3.4 request successful assignment of data variables
  • Step 4: call this method in created
  • Step 5: render data
  • 1 api/user.js package inside
/**
 * Get user's own information
 */
export const getUserChannels = () => {
  return request({
    method: 'GET',
    url: '/v1_0/user/channels'
  })
}

1
2
3
4
5
6
7
8
9

  • 2. Variables defined in data
data () {
    return {
      channels: [] // Channel list
    }
  },

1
2
3
4
5

  • 3. Methods define methods
// Import packaging method
import { getUserChannels } from '@/api/user'

methods: {
    async loadChannels () {
      try {
        // Send a request
        const { data } = await getUserChannels()
        // Successful assignment
        this.channels = data.data.channels
      } catch (err) {
        // Failure handling
        this.$toast('Failed to get channel data')
      }
    }
  }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

  • 4. Called in the life cycle created
 created () {
    this.loadChannels()
  },

1
2
3

  • 5. Render data
 <!-- Channel list -->
    <!--
      animated Sliding animation
      border Bottom border line
      swipeable Turn on left and right gesture sliding
     -->
    <van-tabs  class="channel-tabs" v-model="active" swipeable animated border>

       <van-tab v-for="channel in channels" :key="channel.id" :title="channel.name">
          {{channel.name}}Content of
       </van-tab>

      <!-- ...Other contents -->
    </van-tabs>
    <!-- /Channel list -->

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 3. Article list

# 3.1 analysis of ideas

Your thinking may be like this:

1. Data interface found

2. Encapsulation request method

3. Request to obtain data in the component and store the data in data

4. Template binding display

Load different article lists according to different channels. Your idea may be as follows:

  • There is a list array to store the list of articles
  • View a # channel: request to obtain data and let # list = a # channel article
  • View # b # channel: request to obtain data and let # list = b # channel article
  • View c # channel: request to obtain data and let # list = c # channel article
  • ...

There is no problem with the idea, but it is not the effect we want.

The effect we want is: don't reload the loaded data list.

The implementation idea is also very simple, that is, we prepare multiple list arrays, one for each channel, and store the data in the list array of which channel to view. In this way, the coverage problem will not be caused.

However, there must be as many channel article arrays as there are channels. If we declare them one by one, it will be very troublesome, so the suggestion here is to use components to deal with them.

Specifically:

  • Encapsulate an article list component
  • Then traverse the article list in the channel list

Because the channel id is required to obtain the article list data in the article list component, the channel id should be passed to the article list component as a props parameter. For convenience, we can directly pass the channel object to the article list component.

Request to obtain the corresponding list data in the article list and display it in the list.

Finally, traverse the components in the channel list, as shown below.

# 3.2. Create an article list component

  • 1. Create Src / views / home / components / article list vue
<template>
  <div class="article-list">Article list</div>
</template>

<script>
export default {
  name: 'ArticleList',
  components: {},
  props: {
    // Set up a props to receive its own channel information data  
    channel: {
      type: Object,
      required: true
    }
  },
  data () {
    return {}
  },
  computed: {},
  watch: {},
  created () {},
  mounted () {},
  methods: {}
}
</script>

<style scoped lang="less">
.article-list {
  // The percentage unit is relative to the parent element
  // height: 100%;

  // Viewport (layout viewport at the moving end) units: vw and vh, which are not affected by the parent element
  // 1vw = one percent of the viewport width
  // 1vh = one percent of the viewport height
  height: 79vh;
  overflow-y: auto;
}
</style>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

2. At home / index Vue, import, register and use

3. Finally, through the vue debugger, we can observe whether there are different list components after switching, and whether props has received the corresponding data content.

answering question:

  • Why is label content lazy to render?
    • Because this is the default function supported by the Tab tab component itself, if not required, you can turn off this effect by configuring: lazy render = "false".

# 3.3. Use the List component

List component (opens new window) : waterfall flow scrolling load, which is used to display a long list.

The List component controls the loading status through two variables: loading and finished. When the component initializes or scrolls to the bottom, it will trigger the load event and set the loading to true. At this time, it can initiate asynchronous operation and update the data. After the data is updated, set the loading to false. If all data has been loaded, set finished to true directly.

  • load event:
    • After the List is initialized, a load event will be triggered to load the data of the first screen.
    • If the number of data requested to be loaded at one time is small, so that the List content cannot cover the current screen, the List will continue to trigger the load event until the content covers the screen or all the data are loaded.
  • Loading attribute: controls the loading status during loading
    • In non loading, loading is false. At this time, it will judge whether to trigger the load event according to the rolling position of the list (when the list content is less than one screen, it will be triggered directly)
    • During loading, loading is true, indicating that asynchronous request is being sent, and the load event will not be triggered at this time
  • finished attribute: controls the state of the end of loading
    • After each request, you need to manually set loading to false, indicating that the loading is over
    • When all data is loaded and finished is true, the load event will not be triggered
<template>
  <div class="article-list">
    <!--
      List List component: waterfall flow scrolling loading, which is used to display a long list.

      List Component pass loading and finished Two variables control the loading state,
      Triggered when the component initializes or scrolls to the bottom load Event and will loading Auto set to true,At this point, you can initiate asynchronous operations and update data,
      After the data is updated, the loading Set as false Just.
      If all the data has been loaded, the finished Set as true Just.

      - load event:
        + List It will be triggered once after initialization load Event, used to load the data of the first screen.
        + If the number of data requested to be loaded at one time is small, the list content cannot be covered with the current screen, List Will continue to trigger load Event until the content is covered on the screen or all data is loaded.

      - loading Properties: controlling in loading loading state
        + Not loading, loading by false,At this time, it will judge whether to trigger according to the scroll position of the list load Event (when the list content is less than one screen, it will be triggered directly)
        + Loading, loading by true,Indicates that an asynchronous request is being sent and will not be triggered at this time load event

      - finished Attribute: controls the state of the end of loading
        + After each request, you need to manually loading Set to false,Indicates the end of this loading
        + All data loading ends, finished by true,It is not triggered at this time load event
     -->
    <van-list
      v-model="loading"
      :finished="finished"
      finished-text="No more"
      @load="onLoad"
    >
      <van-cell v-for="item in list" :key="item" :title="item" />
    </van-list>
  </div>
</template>

<script>
export default {
  name: 'ArticleList',
  components: {},
  props: {
    channel: {
      type: Object,
      required: true
    }
  },
  data () {
    return {
      list: [], // An array that stores list data
      loading: false, // Controlling the loading status during loading
      finished: false // Control the status of the end of data loading
    }
  },
  computed: {},
  watch: {},
  created () {},
  mounted () {},
  methods: {
    // The call to onLoad is triggered when initializing or scrolling to the bottom
    onLoad () {
      console.log('onLoad')
      // 1. Request for data
      // setTimeout is just an example. In the real scene, it is generally an ajax request
      setTimeout(() => {
        // 2. Add the request result data into the list array [remember that it is an addition, because only the addition will increase the height of the list]
        for (let i = 0; i < 10; i++) {
          // 0 + 1 = 1
          // 1 + 1 = 2
          // 2 + 1 = 3
          this.list.push(this.list.length + 1)
        }

        // 3. After this data loading, set the loading status to end
        //     The next loading can only be triggered after loading is closed
        this.loading = false

        // 4. Judge whether all data are loaded
        if (this.list.length >= 40) {
          // If there is no data, set finished to true, and then no more loading will be triggered
          this.finished = true
        }
      }, 1000)
    }
  }
}
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

**Home page style adjustment**

.home-container {
  // Leave the bottom fixed navigation bar
  padding-bottom: 100px;
  // Other styles
}

1
2
3
4
5

# 3.4. Load article list data

Realization idea:

  • Data interface found
  • Encapsulation request method
  • Request data
  • Template binding

1. Create Src / API / article JS encapsulates the interface for obtaining article list data

/**
 * Article interface module
 */
import request from '@/utils/request'

/**
 * Get a list of articles for the channel
 */
export const getArticles = params => {
  return request({
    method: 'GET',
    url: '/v1_1/articles',
    params
  })
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Note: use the channel news recommendation at the bottom of the interface document_ V1. one

2. Then request to load the article list when the article list component on the home page is "onload"

<template>
  <div class="article-list">
      <!--
        loading Control pull-up to load more loading state
        finished Control whether the data loading ends
        load Event: when more pull-up loads are triggered, the call will be triggered load event

        List It will be triggered once after initialization load Event, which is used to load the data of the first screen
        If the number of data requested to be loaded at one time is small, the list content cannot be covered with the current screen, List Will continue to trigger load Event until the content is covered on the screen or all data is loaded
      -->
      <van-list
        v-model="loading"
        :finished="finished"
        finished-text="No more"
        :error.sync="error"
        error-text="Request failed, click reload"
        @load="onLoad"
      >
        <van-cell
          v-for="(article, index) in list"
          :key="index"
          :title="article.title"
        />
      </van-list>
  </div>
</template>

<script>
import { getArticles } from '@/api/article'  // < = = = = import method

export default {
  name: 'ArticleList',
  components: {},
  props: {
    // Set up a props to receive its own channel information data    
    channel: {
      type: Object,
      required: true
    }
  },
  data () {
    return {
      list: [], // Article list data
      loading: false, // Pull up to load more loading status
      finished: false, // End of loading
      error: false, // Load failed
      timestamp: null // Timestamp of the data requested for the next page
    }
  },
  methods: {
    // This function is called when more pull-up loads are triggered
    async onLoad () {
      try {
        // 1. Request for data
        const { data } = await getArticles({
          channel_id: this.channel.id, // Channel id
          timestamp: this.timestamp || Date.now(), // Timestamp: request new recommendation data to transmit the current timestamp, and request historical recommendation to transmit the specified timestamp
          with_top: 1 // Whether to include topping. The first request to enter the page should include topping articles, 1-including topping, 0-not
        })

        // 2. Add data to the list array (append!!!)
        const { results } = data.data
        this.list.push(...results)

        // 3. Set the end of loading status in this loading
        this.loading = false

        // 4. Judge whether the data loading is finished (processing page number)
        if (results.length) {
          // Update the timestamp to get the data of the next page
          this.timestamp = data.data.pre_timestamp
        } else {
          // When there is no data, the loading status is set to end, and the pull-up loading will not be triggered any more
          this.finished = true
        }
      } catch (err) {
        console.log(err)
        this.loading = false // Turn off loading effect
        this.error = true // Open error prompt
      }
    }
  }
}
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

Final test.

# 3.5. Pull down refresh

This is mainly used in Vant PullRefresh pull-down refresh (opens new window) Components.

Idea:

  • Register the handler function of the drop-down refresh event (component)
  • Send request to get article list data
  • Add the obtained data to the top of the article list of the current channel
  • Prompt the user to refresh successfully!

During pull-down refresh, the refresh event of the component will be triggered. Synchronous or asynchronous operations can be carried out in the callback function of the event. After the operation is completed, set the refresh event to "v-model" to "false", indicating that the loading is completed.

<van-pull-refresh
      v-model="isreFreshLoading"
      :success-text="refreshSuccessText"
      :success-duration="1500"
      @refresh="onRefresh"
                  >
	 <van-list
        v-model="loading"
        :finished="finished"
        finished-text="No more"
        :error.sync="error"
        error-text="Request failed, click reload"
        @load="onLoad"
               >
    	<!--Other codes-->
    </van-list>
</van-pull-refresh>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

data(){
    return{
        //...  Other variables
       isreFreshLoading: false, // Controls the loading status of the pull-down refresh
       refreshSuccessText: 'Refresh succeeded' // Drop down refresh success prompt text
    }
}


// This function is called when the pull-down refresh is triggered
async onRefresh () {
  try {
    // 1. Request for data
    const { data } = await getArticles({
      channel_id: this.channel.id, // Channel id
      timestamp: Date.now(), // Pull down refresh should get the latest data every time
      with_top: 1 // Whether to include topping. The first request to enter the page should include topping articles, 1-including topping, 0-not
    })

    // 2. Append data to the top of the list
    const { results } = data.data
    this.list.unshift(...results)

    // 3. Turn off the loading status of the pull-down refresh
    this.isreFreshLoading = false

    // Prompt successful
    this.refreshSuccessText = `Refresh succeeded, updated ${results.length}Data bar`
  } catch (err) {
    console.log(err)
    this.isreFreshLoading = false // Turn off the loading status of the pull-down refresh
    this.$toast('refresh failed')
  }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# 3.6 fixed positioning of navigation bar

  1. At home / index Add the fixed attribute to the navigation component of Vue \
<van-nav-bar class="page-nav-bar" fixed>
  <template #title>
    <van-button
      class="search-btn"
      type="info"
      size="small"
      round
      icon="search"
      >search</van-button
    >
  </template>
</van-nav-bar>

1
2
3
4
5
6
7
8
9
10
11
12

  1. Fixed tabs tab
.home-container {
  padding-top: 174px;
  padding-bottom: 100px;
  // tabs tab navigation is also set to fixed positioning
  /deep/ .van-tabs__wrap {
    position: fixed;
    top: 92px;
    z-index: 1;
    left: 0;
    right: 0;
    height: 82px;
  }
}

1
2
3
4
5
6
7
8
9
10
11
12
13

# 3.7. Remember the position of the scroll bar

In the console, use the following code to detect scrolling elements

function findScroller(element) {
  element.onscroll = function () {
     console.log(element)
  }
  Array.from(element.children).forEach(findScroller)
}

findScroller(document.body)

1
2
3
4
5
6
7
8
9
10

Problem: the console shows that each list content scrolls the same element {body, so when switching labels, the last scroll bar position of the list cannot be recorded

Solution: we set a separate scroll bar for the list container of each label, so that when switching between different labels, it will not affect the scrolling position of each other

.article-list {
  // The percentage unit is relative to the parent element
  // height: 100%;

  // Viewport (layout viewport at the moving end) units: vw and vh, which are not affected by the parent element
  // 1vw = one percent of the viewport width
  // 1vh = one percent of the viewport height
  height: 79vh;
  overflow-y: auto;
}

1
2
3
4
5
6
7
8
9
10

# 4. Article list item

# 4.1. Preparation of components

In our project, there are several pages with this article list item. If we write it once in each page, it is not only inefficient, but also troublesome to maintain. So we can use it as the best way to encapsulate the component.

1. Create Src / components / article item / index Vue components

<template>
  <div class="article-item">Article list item</div>
</template>

<script>
export default {
  name: 'ArticleItem',
  components: {},
  props: {
    // Define a props to receive this line of data
    article: {
      type: Object,
      required: true
    }
  },
  data () {
    return {}
  },
  computed: {},
  watch: {},
  created () {},
  mounted () {},
  methods: {}
}
</script>

<style scoped lang="less"></style>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

2. Import, register and use in the article list component

# 4.2. Display the contents of list items

  • Using Cell components
  • Title Display
  • Show bottom information

Adjust based on the following initial structure

<van-cell class="article-item">
  <!-- Title slot -->
  <template #title>
    <div class="title">This is the title</div>
  </template>

  <!-- Below the title -->
  <template #label>
    <!-- Article cover information -->
    <div class="cover-wrap">
      <div class="cover-item">
        <van-image
          width="100"
          height="100"
          src="https://img01.yzcdn.cn/vant/cat.jpeg"
        />
      </div>
    </div>

    <!-- Article annotation information -->
    <div>
      <span>author</span>
      <span>100 comment</span>
      <span>2021-09-01</span>
    </div>
  </template>

  <!-- Default slot: Content on the right -->
  <van-image
    width="100"
    height="100"
    src="https://img01.yzcdn.cn/vant/cat.jpeg"
  />
</van-cell>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

The adjusted layout structure is as follows:

<template>
  <van-cell class="article-item">
    <!-- Title slot -->
    <template #title>
      <div class="title">{{ article.title }}</div>
    </template>

    <!-- Below the title -->
    <template #label>
      <!-- Article cover information -->
      <div v-if="article.cover.type === 3" class="cover-wrap">
        <div
          class="cover-item"
          v-for="(img, index) in article.cover.images"
          :key="index"
        >
          <van-image width="100" height="100" :src="img" />
        </div>
      </div>

      <!-- Article annotation information -->
      <div>
        <span>{{ article.aut_name }}</span>
        <span>{{ article.comm_count }}comment</span>
        <span>{{ article.pubdate }}</span>
      </div>
    </template>

    <!-- Default slot: Content on the right -->
    <van-image
      v-if="article.cover.type === 1"
      width="100"
      height="100"
      :src="article.cover.images[0]"
    />
  </van-cell>
</template>

<script>
export default {
  name: 'ArticleItem',
  components: {},
  props: {
    article: {
      type: Object,
      required: true
    }
  },
  data () {
    return {}
  },
  computed: {},
  watch: {},
  created () {},
  mounted () {},
  methods: {}
}
</script>

<style scoped lang="less"></style>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

# 4.3 style adjustment

  • Article title
    • Font size
    • colour
    • Multiline text ellipsis
  • Single picture cover
    • Cover container
      • Remove flex: 1, fixed width and height
      • Left inner margin
    • Cover picture
      • Width and height
      • Fill mode: cover
  • Bottom text message
    • Font size
    • colour
    • spacing
  • Multi picture cover
    • Outer container
      • flex container
      • Top and bottom outer margin
    • Picture container
      • Average allocated container space: flex: 1;
      • Fixed height
      • Container item spacing
    • picture
      • Width and height
      • Fill mode

The following codes are for reference only.

<template>
  <van-cell class="article-item">
    <!-- Title slot -->
    <template #title>
      <div class="title van-multi-ellipsis--l2">{{ article.title }}</div>
    </template>

    <!-- Below the title -->
    <template #label>
      <!-- Article cover information -->
      <div v-if="article.cover.type === 3" class="cover-wrap">
        <div
          class="cover-item"
          v-for="(img, index) in article.cover.images"
          :key="index"
        >
          <van-image class="cover-item-img" fit="cover" :src="img" />
        </div>
      </div>

      <!-- Article annotation information -->
      <div class="label-info-wrap">
        <span>{{ article.aut_name }}</span>
        <span>{{ article.comm_count }}comment</span>
        <span>{{ article.pubdate }}</span>
      </div>
    </template>

    <!-- Default slot: Content on the right -->
    <van-image
      v-if="article.cover.type === 1"
      class="right-cover"
      fit="cover"
      :src="article.cover.images[0]"
    />
  </van-cell>
</template>

<script>
export default {
  name: 'ArticleItem',
  components: {},
  props: {
    article: {
      type: Object,
      required: true
    }
  },
  data () {
    return {}
  },
  computed: {},
  watch: {},
  created () {},
  mounted () {},
  methods: {}
}
</script>

<style scoped lang="less">
.article-item {
  .title {
    font-size: 32px;
    color: #3a3a3a;
  }

  .van-cell__title {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
  }

  .van-cell__value {
    flex: unset;
    width: 232px;
    height: 146px;
    padding-left: 25px;
  }

  .right-cover {
    width: 100%;
    height: 146px;
  }

  .label-info-wrap span {
    font-size: 22px;
    color: #b4b4b4;
    margin-right: 25px;
  }

  .cover-wrap {
    display: flex;
    padding: 30px 0;
    .cover-item {
      flex: 1;
      height: 146px;
      &:not(:last-child) {
        padding-right: 4px;
      }
      .cover-item-img {
        width: 100%;
        height: 146px;
      }
    }
  }
}
</style>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

# 4.4. 403 problems of third-party picture resources

Why do many picture resource requests in the article list data fail and return 403?

This is because the interface data of our project is the content of the third-party platform captured by the back-end through the crawler, and the third-party platform has done anti-theft chain protection processing for the image resources.

1

How does the third-party platform deal with the protection of image resources?

General use of server Referer The request header identifies the source of access and then handles resource access.

1

What is a Referer?

Extended reference: http://www.ruanyifeng.com/blog/2019/06/http-referer.html

Referer yes HTTP Part of the request header when the browser Web When the server sends a request, it usually brings it with it Referer,It contains the address of the source page of the currently requested resource. General use of server Referer The request header identifies the access source, which may be used for statistical analysis, logging and cache optimization.

1

It should be noted that referer is actually a misspelling of "referer". See HTTP referer on Wikipedia (opens new window) (HTTP referer entry on Wikipedia) to get more detailed information.

How?

Don't send referrer ,The other party's server doesn't know where you came from. Let's think you're your own.

1

How to set not to send referrer?

Use the "referrpolicy" attribute on the < a >, < area >, < img >, < iframe >, < script > or < link > element to set an independent request policy for it, for example:

<img src="http://......" referrerPolicy="no-referrer">

1

Or you can directly configure public / index.xml in the HTMl page header through the meta attribute Write the following in HTMl:

<meta name="referrer" content="no-referrer" />

1

# 4.5 relative processing time

Two third-party libraries are recommended:

Both are JavaScript libraries dedicated to processing time, with similar functions, because day JS design is the reference moment js. But day JS compared to moment JS has a smaller package size because it adopts a plug-in processing method.

Day.js (opens new window) Is a lightweight JavaScript library that handles time and date, and Moment.js (opens new window) The API design remains exactly the same if you have ever used moment JS, then you already know how to use day js .

  • Day.js can run in browser and node JS.

  • 🕒 And moment JS has the same API and usage

  • 💪 Immutable data

  • 🔥 Support chain operation (Chainable)

  • 🌐 International I18n

  • 📦 2kb mini library only

  • 👫 Full browser compatibility

1. Installation

npm i dayjs

1

2. Create utils / dayjs js

Relative time document (opens new window)

Configuration language pack documentation (opens new window)

import Vue from 'vue'
import dayjs from 'dayjs'

// Load Chinese language pack
import 'dayjs/locale/zh-cn'

import relativeTime from 'dayjs/plugin/relativeTime'

// Configure plug-ins that use relative processing time
dayjs.extend(relativeTime)

// Configure to use Chinese language pack
dayjs.locale('zh-cn')

// Global filters: processing relative time
Vue.filter('relativeTime', value => {
  return dayjs().to(dayjs(value))
})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

3. In main JS

import './utils/dayjs'

1

4. Use

Use filters:

<span>{{ article.pubdate | relativeTime }}</span>

Topics: Javascript Front-end css