摘要

本文介绍了setup支持的组合式api的两个好处。

内容

•业务分离•组合

业务分离

下面是一段描述vue2代码的伪代码

new Vue({    data () {    数据项1:[],    数据项2:{}  },  methods: {   与数据1相关的操作 () {}   与数据2相关的操作 () {}  },  computed: {   与数据1相关的计算属性:(){}   与数据2相关的计算属性:(){}  }})

缺点:与数据1相关的代码分散在不同的配置项中,并没有集中起来,不方便写代码:你往往需在不同配置项中跳转。例如:添加一个数据要去data中,添加对应的操作方法要在methods中.....。

在vue3,我们可以这样写

const use数据项1 = function() {  const 数据项1 = reactive({})  const 计算属性1 = computed(()=>{})  const 操作1 = ()=>{}    return {数据项1, 计算属性1,操作1}}const use数据项2 = function() {    return {数据项2, 计算属性2,操作2}}new Vue({    data () {},  setup () {    const { 数据项1, 计算属性1,操作1 } = use数据项1()    const { 数据项2, 计算属性2,操作2 } = use数据项2()    return { 数据项1, 计算属性1,操作1 , 数据项2, 计算属性2,操作2}    }})

它的典型特点是,可以把业务相关的代码在放在同一个位置来写。

用vue2写的todolist

<!DOCTYPE html><html lang="zh"><head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>html页面</title> <script src="https://cdn.jsdelivr.net/npm/vue"></script> </head> <body>   <div id="app">     <h2>vue2的todolist</h2>     <ul>       <li         v-for="item in list"        :key="item.id"        > <input type="checkbox" @click="hSwitchStatus(item)" :checked="item.isDone"/> {{item.content}}</li>     </ul>     <hr>     <div>      内容<input type="text" v-model="todo.content"> <br>      <input type="submit" @click.prevent="hAdd" value="添加">     </div>   </div>   <script>      const initData = [        {id:1, content: '下载vue3', isDone: true},        {id:2, content: '使用setup', isDone: false},        {id:3, content: '使用mock', isDone: false},      ]      function mockData () {        return new Promise((resolve,reject) => {          setTimeout(() => {            resolve(initData)          }, 1000)        })      }      new Vue({        el: "#app",        data() {          return {            todo: {              content: ''            },            list: []          }        },        async mounted (){          this.list = await mockData()          console.log(this.list)        },        methods: {          hSwitchStatus (item) {            item.isDone = !item.isDone          },          hAdd() {            this.list.push({              id: !this.list.length ? 1: this.list[this.list.length-1].id+1,              content: this.todo.content,              isDone: false            })          }        }      })   </script> </body></html>

用vue3写的todolist-改进版本

<!DOCTYPE html><html lang="zh"><head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>html页面</title> <script src="https://unpkg.com/vue@next"></script> </head> <body>   <div id="app">     <h2>解决数据和业务逻辑分离的问题</h2>     <ul>       <li         v-for="item in list"        :key="item.id"        > <input type="checkbox" @click="hSwitchStatus(item)" :checked="item.isDone"/> {{item.content}}</li>     </ul>     <hr>     <div>      内容<input type="text" v-model="todo.content">       <input type="submit" @click.prevent="hAdd" value="添加">     </div>   </div>   <script>      const initData = [        {id:1, content: '学习vue3', isDone: true},        {id:2, content: '学习vue3', isDone: false},        {id:3, content: '学习vue3', isDone: false},      ]      function mockData () {        return new Promise((resolve,reject) => {          setTimeout(() => {            resolve(initData)          }, 1000)        })      }      function useList () {        const list = Vue.ref([])        const hSwitchStatus =  item => {          item.isDone = !item.isDone        }        const getData = async () => {          const rs = await mockData()          list.value = rs        }        return { list, getData, hSwitchStatus }      }




      function useAdd (list) {        const todo = Vue.reactive({            content: ''          })        const hAdd = () => {          // const {content} = Vue.toRefs(todo)          list.value.push({            id: !list.value.length ? 1: list.value[list.value.length-1].id+1,            content: todo.content,            isDone: false          })        }        return { todo, hAdd }      }      const ToDoLIST = {        data() {          return {}        },        setup (){          const { getData, list, hSwitchStatus } = useList()          const { hAdd, todo } = useAdd(list)          Vue.onMounted(getData)          return {            list, todo, hAdd, hSwitchStatus          }        }        }      const vm = Vue.createApp(ToDoLIST).mount('#app')      console.log(vm)   </script> </body></html>

逻辑复用

vue2中的写法

在vue2中逻辑复用可以采用mixins来实现。例如,定义如下mixins:

const mouseposition = {        data () {          return {            x: 0,            y: 0          }        },        methods: {          update(e) {            this.x = e.pageX            this.y = e.pageY          }        },        mounted () {           // 提取为函数          window.addEventListener('mousemove', this.update)        },        beforeDestoryed() {          window.removeEventListener('mousemove', this.update)        }      }

用来它实时获取鼠标的位置,并保存到数据项中。如果在当前的某个应用中也需要用到获取鼠标位置的功能,则可以直接通过mixins来混入。步骤分成两步:

1.引入mixins2.在视图(代码)中使用x,y

new Vue({mixins: [mouseposition],//..})

 

示例:下面的例子完整演示了mixin的用法

<!DOCTYPE html><html lang="zh"><head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>html页面</title> <script src="https://cdn.jsdelivr.net/npm/vue"></script> </head> <body>   <div id="app">     <h2>mixin复用逻辑</h2>     {{x}}-{{y}}     <ul>       <li         v-for="item in list"        :key="item.id"        > <input type="checkbox" @click="hSwitchStatus(item)" :checked="item.isDone"/> {{item.content}}</li>     </ul>     <hr>     <div>      内容<input type="text" v-model="todo.content"> <br>      <input type="submit" @click.prevent="hAdd" value="添加">     </div>   </div>   <script>      const mouseposition = {        data () {          return {            x: 0,            y: 0          }        },        methods: {          update(e) {            this.x = e.pageX            this.y = e.pageY          }        },        mounted () {          window.addEventListener('mousemove', this.update)        },        beforeDestory() {          window.removeEventListener('mousemove', this.update)        }      }      const initData = [        {id:1, content: '下载vue3', isDone: true},        {id:2, content: '使用setup', isDone: false},        {id:3, content: '使用mock', isDone: false},      ]      function mockData () {        return new Promise((resolve,reject) => {          setTimeout(() => {            resolve(initData)          }, 1000)        })      }      new Vue({        el: "#app",        mixins: [mouseposition], // 混入        data() {          return {            todo: {              content: ''            },            list: []          }        },        async mounted (){          this.list = await mockData()          console.log(this.list)        },        methods: {          hSwitchStatus (item) {            item.isDone = !item.isDone          },          hAdd() {            this.list.push({              id: !this.list.length ? 1: this.list[this.list.length-1].id+1,              content: this.todo.content,              isDone: false            })          }        }      })   </script> </body></html>

上面的代码是可以工作的,但是有个非常不好的体验:mixins中的data会混入到当前组件中,但是由于并没有显式声明这个数据源,会导致在当前组件根本无法得知某个mixin到底混入了哪些数据。 下面来看,如果在vue3中应该如何解决。

const useMousePosition = function (){  const x = Vue.ref(0)  const y = Vue.ref(0)   // 提取为函数  function update(e) {    x.value = e.pageX    y.value = e.pageY  }  Vue.onMounted(() => {    window.addEventListener('mousemove', update)  })  Vue.onUnmounted(() => {    window.removeEventListener('mousemove', update)  })  return { x, y }}代码如下:<!DOCTYPE html><html lang="zh"><head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>html页面</title> <script src="https://unpkg.com/vue@next"></script> </head> <body>   <div id="app">     <h2>逻辑复用</h2>     {{x}}-{{y}}     <ul>       <li         v-for="item in list"        :key="item.id"        > <input type="checkbox" @click="hSwitchStatus(item)" :checked="item.isDone"/> {{item.content}}</li>     </ul>     <hr>     <div>      内容<input type="text" v-model="todo.content">       <input type="submit" @click.prevent="hAdd" value="添加">     </div>   </div>   <script>const useMousePosition = function (){  const x = Vue.ref(0)  const y = Vue.ref(0)  function update(e) {    x.value = e.pageX    y.value = e.pageY  }  Vue.onMounted(() => {    window.addEventListener('mousemove', update)  })  Vue.onUnmounted(() => {    window.removeEventListener('mousemove', update)  })  return { x, y }}      const initData = [        {id:1, content: '学习vue3', isDone: true},        {id:2, content: '学习vue3', isDone: false},        {id:3, content: '学习vue3', isDone: false},      ]      function mockData () {        return new Promise((resolve,reject) => {          setTimeout(() => {            resolve(initData)          }, 1000)        })      }      function useList () {        const list = Vue.ref([])        const hSwitchStatus =  item => {          item.isDone = !item.isDone        }        const getData = async () => {          const rs = await mockData()          list.value = rs        }        return { list, getData, hSwitchStatus }      }      function useAdd (list) {        const todo = Vue.reactive({            content: ''          })        const hAdd = () => {          // const {content} = Vue.toRefs(todo)          list.value.push({            id: !list.value.length ? 1: list.value[list.value.length-1].id+1,            content: todo.content,            isDone: false          })        }        return { todo, hAdd }      }      const ToDoLIST = {        data() {          return {}        },        setup (){          const { getData, list, hSwitchStatus } = useList()          const { hAdd, todo } = useAdd(list)          // 混入          const { x, y } = useMousePosition()          Vue.onMounted(getData)          return {            list, todo, hAdd, hSwitchStatus, x,y          }        }        }      const vm = Vue.createApp(ToDoLIST).mount('#app')      console.log(vm)   </script> </body></html>

小结

setup是组合式api的入口,相比vue2它可以可以将不同的业务分离,并有更好的逻辑复用的体验。确实值得拥有。

Logo

前往低代码交流专区

更多推荐