preface

This article will take you to realize the choice of address, register it as a global component, select the address after three linkage. Take a look


A, preparation,

1. axios

Send a request using Axios to get all the city data

  • Open any terminal in the project root directory and run the NPM I axios command

  • The code in the project that needs to send requests is placed in the SRC/API directory, where a new index.js file is created

import axios from 'axios'
// Get city data
1. Where is the data? https://yjy-oss-files.oss-cn-zhangjiakou.aliyuncs.com/tuxian/area.json
// 2. When to obtain? Make an in-memory cache when opening the list of cities
// 3. How to use data? Define calculated properties, displayed by clicking on the province city
export const getCityList = async() = > {// Add a cache to prevent frequent loading of list data
  if (window.cityList) {
    // Data already exists in the cache
    return window.cityList
  }
  const ret = await axios.get('https://yjy-oss-files.oss-cn-zhangjiakou.aliyuncs.com/tuxian/area.json')
  // Add an attribute cityList to the window object
  if (ret.data) {
    window.cityList = ret.data
  }
  // Return the data
  return ret.data
}
Copy the code

2. vueuse/core

Use onClickOutside in Vueuse/Core to determine if the component is clicked outside to help turn off the bounce layer

On the terminal, run NPM install@vueuse /[email protected] to install the specified version. You can choose as required

Two, code implementation

1. The encapsulation

Encapsulate it as a global component and, as in the previous article, place the file in the SRC/Components directory and create a new city.vue file

The code is as follows (example) :

<template>
  <div class="city" ref="target">
    <div class="select" @click="toggle" :class="{active:isShow}">
      <span v-if='! fullLocation' class="placeholder"> Please select shipping address </span> <span v-else class="value">{{fullLocation}}</span>
      <i class="iconfont icon-angle-down"></i> </div> <! --> <div class="option" v-show='isShow'> <! --> <div class="loading" v-if='loading'></div>
      <template v-else>
        <span @click='changeCity(item)' class="ellipsis" v-for="item in cityList" :key="item.code">{{item.name}}</span>
      </template>
    </div>
  </div>
</template>

<script>
import { ref, reactive, computed } from 'vue'
import { onClickOutside } from '@vueuse/core'
import { getCityList } from '@/api'
export default {
  name: 'City',
  props: {
    fullLocation: {
      type: String,
      default: ' '
    }
  },
  setup (props, { emit }) {
    const isShow = ref(false)
    const loading = ref(falseConst list = ref([]) const changeResult = reactive({provinceCode:' ',
      provinceName: ' ',
      cityCode: ' ',
      cityName: ' ',
      countyCode: ' ',
      countyName: ' ',
      fullLocation: ' '}) // Select city const changeCity = (city) => {if(city) level = = = 0) {/ / click provincial units changeResult provinceCode = city. The code changeResult. ProvinceName = city. The name}else ifCityCode = city.code Changeresult. cityName = city.name}else if(city.level === 2) {// Click on the county unit: select the final provincial data, And passed to the parent component changeResult. CountyCode = city. The code changeResult. CountyName = city. The name / / full name of the provinces, changeResult. FullLocation = `${changeResult.provinceName}${changeResult.cityName}${changeResult.countyName}'// Close the carbon layer isshow. value =false// Finally pass the selected data to the parent emit('change-city', changeResult)}} // Calculate the list data currently displayed by calculating attributes: provincial; At the municipal level. County-level const cityList = computed(() => {letResult = list.value // the current click is province, then calculate city listif (changeResult.provinceCode && changeResult.provinceName) {
        result = result.find(item => item.code === changeResult.provinceCode).areaList
      }
      if(changeResult.cityCode && changeResult.cityName) { result = result.find(item => item.code === Changeresult.citycode).arealistreturnConst toggle = () => {isshow.value =! isShow.valueif (isShow.value) {
        loading.value = true// Empty the previously selected data before calling the interfacefor (const key in changeResult) {
          changeResult[key] = ' '} // The elastic layer is displayed, calling the interface getCityList().then(ret => {
          list.value = ret
          loading.value = falseConst target = ref(null) onClickOutside(target, () => {isshow.value =false
    })
    return { isShow, toggle, target, cityList, loading, changeCity }
  }
}
</script>

<style scoped lang="less">
.city {
  display: inline-block;
  position: relative;
  z-index: 400;
  .select {
    border: 1px solid #e4e4e4;
    height: 30px;
    padding: 0 5px;
    line-height: 28px;
    cursor: pointer;
    &.active {
      background: #fff;
    }
    .placeholder {
      color: # 999;
    }
    .value {
      color: # 666;
      font-size: 12px;
    }
    i {
      font-size: 12px;
      margin-left: 5px;
    }
  }
  .option {
    width: 542px;
    border: 1px solid #e4e4e4;
    position: absolute;
    left: 0;
    top: 29px;
    background: #fff;
    min-height: 30px;
    line-height: 30px;
    display: flex;
    flex-wrap: wrap;
    padding: 10px;
    .loading {
      height: 290px;
      width: 100%;
      background: url(https://code-1307161657.cos.ap-beijing.myqcloud.com/images%2Fload.gif) no-repeat center;
    }
    > span {
      width: 130px;
      text-align: center;
      cursor: pointer;
      border-radius: 4px;
      padding: 0 3px;
      &:hover {
        background: #f5f5f5;
      }
    }
  }
}
</style>

Copy the code

As in previous articles, register as a global component in index.js under SRC/Components and as a plug-in in main.js (I won’t demonstrate this here).

2. Use

Use in any.vue ending file

If there is default data, you can pass the default data to the child component code as follows (example) :

<template>
  <div class="home-banner">
    <city @change-city='changeCity' :fullLocation='fullLocation' />
  </div>
</template>

<script>
import { ref } from 'vue'
export default {
  name: 'App',
  props: {
    goods: {
      type: Object,
      default: () => { }
    }
  },
  setup () {
    const provinceCode = ref('110000')
    const cityCode = ref('119900')
    const countyCode = ref('110101')
    // const fullLocation = ref('Dongcheng District, Beijing Municipal District')
    const fullLocation = ref(' 'Const changeCity = (cityInfo) => {provincecode. value = cityinfo.provincecode citycode. value = cityInfo.cityCode countyCode.value = cityInfo.countyCode fullLocation.value = cityInfo.fullLocation }return { fullLocation, changeCity }
  }
}
</script>

<style lang="less">
.home-banner {
  width: 1000px;
  margin: 50px auto;
}

</style>

Copy the code

Third, the effect demonstration


conclusion

There have been several articles about vue3’s own packaged components, which you can check out on my home page