Cover image from the Internet, delete

Future-oriented Programming, vuE-function-API provides developers to develop applications using Vue3 syntactic logic in Vue2. X. (Denoted as Vue2 for convenience)

This article will not explain much about the documentation API, but only the problems encountered in project practice. Comparing the difference between the two is the fastest understanding of the writing method of Vue3. The following is the difference between Vue2 and Vue3 by comparing the same function.

The scenario is as follows: a list page, the top part of which is a filter, the bottom part of which is a table, and the table row will be deleted and modified (displayed as a dialog). The template section is the same, so I won’t go into details here.

The preparatory work

Install the vue function – API

npm install vue-function-api --save

#or
yarn add vue-function-api
Copy the code

Introduce main.js in your project

import Vue from 'vue'
import Element from 'element-ui'
import { plugin } from 'vue-function-api' // <-- introduce vue-function-api

import App from './App'
import router from './router'
import store from './store'

Vue.use(Element)
Vue.use(plugin) // <-- this allows you to use functional apis in single-file components

Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h= > h(App),
}).$mount('#app')
Copy the code

After the preparation, you can do the comparison in peace.

data

In Vue2, we first define data. In Data, we define a Query object for the condition filtering, citys for the city in the condition filtering (dynamic get drop down), statusMap for the state in the condition filtering, list for the table.

export default {
  data() {
    return {
      query: {
        city: null.name: null.status: null
      },
      citys: [].list: [].statusMap:  [{
        value: 1.label: 'enable'
      }, {
        value: 2.label: 'disabled'}}}]Copy the code

This is defined in Vue3

import { value } from 'vue-function-api'

export default {
  setup() {
    const query = value({
      city: null.name: null.status: null
    })
    const citys = value([])
    const list = value([])
    const statusMap = value([{
      value: 1.label: 'enable'
    }, {
      value: 2.label: 'disabled'
    }])

    return {
      query,
      citys,
      list,
      statusMap
    }
  }
}
Copy the code

If you’re careful, you’ll notice that after setup, you need variables defined by return. You don’t need to put all variables in return, you put them in return so that you can use them in template. That is, only the dependent variable in the return template

computed

As mentioned above, table has deletion and editing functions. In normal systems, such functions need to be operated by people with permissions. Here, we assume that permissions have been stored in VUex. The permissions need to be retrieved by mapGetters (for example, normal permissions are more complex).

It’s written like this in Vue2

import { mapGetters } from 'vuex'

export default {
  // The data part is omitted here...computed: { ... mapGetters(['permissions']),
    canUpdate() {
      return this.permissions.includes('update')
    },
    canDelete() {
      return this.permissions.includes('delete')}},// ...
}

Copy the code

Vue3: Currently vuE-function-API does not support vuex map to export state in vuex. Here we extract store data from vue root

import { computed } from 'vue-function-api'

export default {
  setup(props, ctx) {
    const { $store } = ctx.root
    // The data part is omitted here...

    const permissions = computed((a)= > $store.getters.permissions)
    const canUpdate = (a)= > permissions.includes('update')
    const canDelete = (a)= > permissions.includes('delete')

    return {
      canUpdate,
      canDelete // <-- export template dependency only}}}Copy the code

In template, add v-if=”canUpdate” and v-if=”canDelete” to the edit and delete buttons, respectively.

methods & lifecycle

Based on the description above, lifecycle will be compared with Lifecycle as it is a list page.

In Vue2

export default {
  // ...

  methods: {
    async fetchCity() {
      const response = await fetchCityApi()
      this.citys = response.data
    },

    async fetchList() {
      const response = await fetchListApi(this.query)
      this.list = response.data
    },

    async delete(id) {
      const response = await deleteItem(id)
      const { status, msg } = response.data
      if(status ! = ='ok') return this.$message.error(msg)
      this.$message({
        type: 'success'.message: 'Deleted successfully'
      })
    },

    confirm(id) {
      this.$confirm('Confirm deletion'.'tip', {
        confirmButtonText: 'sure'.cancelButtonText: 'cancel'.type: 'warning'
      }).then((a)= > {
        this.delete(id)
      }).catch((a)= > {
        this.$message({
          type: 'info'.message: 'Cancelled'
        })
      })
    },

    detail(id) {
      this.$router.push({
        path: '/detail'.query: { id }
      })
    }
  }
}

  created() {
    this.fetchCity()
    this.fetchList()
  }
}
Copy the code

Next, look at the Vue3 implementation

import { computed, onCreated } from 'vue-function-api'

export default {
  setup(props, ctx) {
    const { $message, $router, $confirm, $store } = ctx.root // <-- setup() cannot use this to access the current component instance. You can use context, the second argument to setup, to access properties on the instance in the vue2.x API.
    // The data part is omitted here...

    // method
    const fetchCity = async() = > {const response = await fetchCityApi()
      citys.value = response.data / / < - highlighted by the value (wrap) initialize variables in the setup of the internal reference value to add or modify values. The value
    },

    const fetchList = async() = > {const response = await fetchListApi(query.value)
      list.value = response.data
    },

    const delete = async id => {
      const response = await deleteItem(id)
      const { status, msg } = response.data
      if(status ! = ='ok') return $message.error(msg)
      $message({
        type: 'success'.message: 'Deleted successfully'
      })
    },

    confirm(id) {
      $confirm('Confirm deletion'.'tip', {
        confirmButtonText: 'sure'.cancelButtonText: 'cancel'.type: 'warning'
      }).then((a)= > {
        delete(id)
      }).catch((a)= > {
        $message({
          type: 'info'.message: 'Cancelled'
        })
      })
    },

    detail(id) {
      $router.push({
        path: '/detail'.query: { id }
      })
    }

    // lifecycle
    onCreated((a)= > {
      fetchCity()
      fetchList()
    })

    return {
      fetchCity,
      fetchList,
      confirm,
      detail // <-- export template dependency only}}}Copy the code

Does it feel like switching to Vue3 isn’t that hard

watch

The watch example might not have any usage scenarios in a list page, but the list page has a condition filter, a city drop down, a state drop down, and of course normally we call the fetchList with the change event of the select, so I’m just going to write this for example, Actual projects weigh their own pros and cons.

In Vue2

export default {
  // ...

  watch: {
    query: {
      handler: function(val) {
        this.fetchList()
      },
      { deep: true}}}// Or take the trouble to write...
  watch: {
    'query.city': function(val) {
      this.fetchList()
    },
    'query.name': function(val) {
      this.fetchList()
    },
    'query.status': function(val) {
      this.fetchList()
    }
  }

  // ...
}
Copy the code

In Vue3

import { watch } from 'vue-function-api'

export default {
  setup() {
    // ...

    watch(
      query,
      val => {
        fetchList()
      },
      { deep: true})/ / or

    watch(
      (a)= > query.value,
      val => {
        fetchList()
      },
      { deep: true})// ...}}Copy the code

Vue3 is a list page. It doesn’t use provide, inject, and state, which is equivalent to vue.Observable.

Compare complete code

Vue2

export default {
  data() {
    return {
      query: {
        city: null.name: null.status: null
      },
      citys: [].list: [].statusMap:  [{
        value: 1.label: 'enable'
      }, {
        value: 2.label: 'disabled'}}},computed: {
    ...mapGetters(['permissions']),
    canUpdate() {
      return this.permissions.includes('update')
    },
    canDelete() {
      return this.permissions.includes('delete')}},methods: {
    async fetchCity() {
      const response = await fetchCityApi()
      this.citys = response.data
    },

    async fetchList() {
      const response = await fetchListApi(this.query)
      this.list = response.data
    },

    async delete(id) {
      const response = await deleteItem(id)
      const { status, msg } = response.data
      if(status ! = ='ok') return this.$message.error(msg)
      this.$message({
        type: 'success'.message: 'Deleted successfully'
      })
    },

    confirm(id) {
      this.$confirm('Confirm deletion'.'tip', {
        confirmButtonText: 'sure'.cancelButtonText: 'cancel'.type: 'warning'
      }).then((a)= > {
        this.delete(id)
      }).catch((a)= > {
        this.$message({
          type: 'info'.message: 'Cancelled'
        })
      })
    },

    detail(id) {
      this.$router.push({
        path: '/detail'.query: { id }
      })
    }
  },
  created() {
    this.fetchCity()
    this.fetchList()
  },
  watch: {
    query: {
      handler: function(val) {
        this.fetchList()
      },
      { deep: true}}}Copy the code

Vue3

import { value, computed, onCreated } from 'vue-function-api'

export default {
  setup(props, ctx) {
    const { $store, $message, $router, $route } = ctx.root
    // reactive state
    const query = value({
      city: null.name: null.status: null
    })
    const citys = value([])
    const list = value([])
    const statusMap = value([{
      value: 1.label: 'enable'
    }, {
      value: 2.label: 'disabled'
    }])

    // computed
    const permissions = computed((a)= > $store.getters.permissions)
    const canUpdate = (a)= > permissions.includes('update')
    const canDelete = (a)= > permissions.includes('delete')

    // method
    const fetchCity = async() = > {const response = await fetchCityApi()
      citys.value = response.data
    },

    const fetchList = async() = > {const response = await fetchListApi(query.value)
      list.value = response.data
    },

    const delete = async id => {
      const response = await deleteItem(id)
      const { status, msg } = response.data
      if(status ! = ='ok') return $message.error(msg)
      $message({
        type: 'success'.message: 'Deleted successfully'
      })
    },

    confirm(id) {
      $confirm('Confirm deletion'.'tip', {
        confirmButtonText: 'sure'.cancelButtonText: 'cancel'.type: 'warning'
      }).then((a)= > {
        delete(id)
      }).catch((a)= > {
        $message({
          type: 'info'.message: 'Cancelled'
        })
      })
    },

    detail(id) {
      $router.push({
        path: '/detail'.query: { id }
      })
    }

    // watch
    watch(
      query,
      val => {
        fetchList()
      },
      { deep: true})// lifecycle
    onCreated((a)= > {
      fetchCity()
      fetchList()
    })

    return {
      query,
      citys,
      list,
      statusMap,
      canUpdate,
      canDelete,
      fetchCity,
      fetchList,
      confirm,
      detail
    }
  }
}
Copy the code

The last

Context, the second parameter in setup, has properties that are a subset of vue instance properties in 2.x. Complete property list:

  • parent
  • root
  • refs
  • slots
  • attrs
  • emit

Like other libraries vuex, VUe-Router, ElementUI some $methods are available from root

export default {
  setup(props, ctx) {
    const { $store, $router, $route, $message, $confirm } = ctx.root
  }
}
Copy the code

The last

The author has used the formal environment, so far there is no problem, citing the official description of vue-function-API

Vue-function-api will always be compatible with vue3.x, and you can seamlessly replace the library when 3.0 is released. The implementation of vue-function-API only depends on vue2. x itself. Whether vue3. x is released or not, it will not affect your normal use of the library. Due to the limitations of Vue2. X’s public API, vue-function-API inevitably imposes some additional memory load. If your application does not work in an extreme memory environment, don’t worry about this.

The Vue Function API uses function-based apis to reuse component logic