episode

We are preparing a name for our front end group recently. We welcome your vote and suggestions. Now we have two proposals

  1. Front-end Independents. I’m a real fucking genius but I don’t have a domain name yet
  2. Record video team, Lsp.team

Supporting code github

Recently, Da Shuai *, a student in our group, wrote a very good composition and animation demonstration article, but everyone said it was too short. I hope you can understand that he was forced to write the article recently, and the subsequent article will be more complete. I have given him too many tasks recently, so let me help him to simply enrich the meaning of this article

This article is actually very simple, and it’s great to illustrate the benefits of composition. We used a very simple panacea scenario, like we had a very simple Todo list

Review the Option

<template>
  <div id="app">
    <input type="text" v-model="val" @keyup.enter="addTodo">
    <ul>
      <li v-for="todo in todos" :key="todo.id">{{todo.title}}</li>
    </ul>
  </div>
</template>
<script>
export default {
  data(){
    return{
      val:' '.todos:[ 
        {id:0.title:'eat'.done:false},
        {id:1.title:'sleep'.done:false},
        {id:2.title:'lsp'.done:false}}},],methods: {addTodo(){
      this.todos.push({
        id:this.todos.length,
        title:this.val,
        done:false
      })
      this.val = ' '}}}</script>

Copy the code

When the requirements are complicated, watch, computed, inject, provide and other configurations are added, and the.vue file grows

Drawback of Option – repeated hop

I’m sure most of you have maintained more than 200 lines of vUE components. If you add or modify a requirement, you need to do it in data, methods, and computed, and the scrollbar moves up and down repeatedly, which I call “repeated horizontal hop”. For example, if we simply add a tap on the forehead and an accumulator, I’m sure you all know that feeling of writing code up and down,

The demo

<template>
  <div id="app">
    <h1 @click="add">LSP {{count}} double is{{double}}</h1>
    <input type="text" v-model="val" @keyup.enter="addTodo">
    <ul>
      <li v-for="todo in todos" :key="todo.id">{{todo.title}}</li>
    </ul>
  </div>
</template>

<script>
import Counter from './counter'
export default {
  mixins:[Counter],
  data(){
    return{
      count:1.val:' '.todos:[ 
        {id:0.title:'eat'.done:false},
        {id:1.title:'sleep'.done:false},
        {id:2.title:'lsp'.done:false}}},],computed: {
    double() {
      return this.count * 2}},methods: {addTodo(){
      this.todos.push({
        id:this.todos.length,
        title:this.val,
        done:false
      })
      this.val = ' '
    },
    add(){
      this.count++
    }
  }
}
</script>
Copy the code

Disadvantages of Options: mixin and this

The nature of repeated horizontal hopping lies in the function partition organization and the large amount of code. If we can control the code in one screen, it will be solved naturally. The solution in VUe2 is to use mixin to mix, and we pull out a counter.js

export default {
  data() {
    return {
      count:1}},computed: {
    double() {
      return this.count * 2}},methods: {add(){
      this.count++
    }
  }
}
Copy the code

In the App. In vue

import Counter from './counter'
export default {
  mixins:[Counter],
  data(){... },... }Copy the code

This does split the code, but there is a serious problem, is not open counter. Js, app. vue this, count, add attributes, you do not know where they come from, you do not know whether it is mixin, or global install, This is a black box, and the template contains count and double, so I don’t know where it came from

Mixin naming conflict

It would be even more interesting if we had two mixins, such as a requirement to display the mouse’s coordinate position xin real time, and a calculation property multiplied by two, coincidentally also called double, and a mixin

export default {
  data() {
    return {
      x:0}},methods: {update(e){
      this.x = e.pageX
    }
  },
  computed: {double(){
      return this.x*2}},mounted(){
    window.addEventListener('mousemove'.this.update)
  },
  destroyed(){
    window.removeEventListener('mousemove'.this.update)
  }
}

Copy the code

This is a independently maintained mixin, may be used in N places, he does not know whether someone will conflict with him, and then use it

import Counter from './counter'
import Mouse from './mouse'
export default {
  mixins:[Counter,Mouse],
  ...... 
}
Copy the code

There is double in both mixins, which is embarrassing. Look at the effect, the count of LSP is overwritten, which is embarrassing. In app. vue, you have no idea which double is exactly, debugging is very painful

Composition

Composition is to solve this problem. By means of combination, the codes scattered in various data and methods are recombined, and the codes of a function are maintained together, and these codes can be separately divided into functions, namely the two GIFs of Da Shuai

Let’s use VUe3 to demonstrate the function, the specific API does not explain the direct vue3 documentation can be

<template>
  <div id="app">
    <input type="text" v-model="val" @keyup.enter="addTodo">
    <ul>
      <li v-for="todo in todos" :key="todo.id">{{todo.title}}</li>
    </ul>
  </div>
</template>

<script>
import {reactive, ref, toRefs} from 'vue'

export default {
  setup(){
    let val = ref(' ')
    let todos = reactive([ 
        {id:0.title:'eat'.done:false},
        {id:1.title:'sleep'.done:false},
        {id:2.title:'lsp'.done:false},])function addTodo(){
      todos.push({
        id:todos.length,
        title:val.value,
        done:false
      })
      val.value = ' '
    }
    return {val, todos, addTodo}
  }
}
</script>

Copy the code

By using functions, we can divide functions into modules or functions completely and independently, which is convenient for code organization and solves the problem of mixin confusion

For example, our accumulator pulls out a counter.js


import {ref, computed} from 'vue'

export default function useCounter(){
    let count = ref(1)
    function add(){
        count.value++
    }
    let double = computed(() = >count.value*2)
    return {count, double, add}
}


Copy the code

Direct use of

import {reactive, ref, toRefs} from 'vue'
+ import useCounter from './counter'
export default {
  setup(){
    let val = ref('')
	...
+ let {count,double,add} = useCounter()
    return {
      val, todos, addTodo,
+ count,double,add}}}Copy the code

Another mouse position is not a problem, and the alias of the deconstructed assignment is a good way to resolve the naming conflicts of the mixin, mouse.js

import {ref, onMounted, onUnmounted, computed} from 'vue'

export default function useMouse(){
  let x = ref(0)
  function update(e){
    x.value = e.pageX
  }
  let double = computed(() = >x.value*2)
  onMounted(() = >{
    window.addEventListener('mousemove', update)
  })
  onUnmounted(() = >{
    window.removeEventListener('mousemove', update)
  })
  return {x, double}
  
}
Copy the code

Use doubelX directly in the template

let {count,double,add} = useCounter() 
let {x, double:doubleX} = useMouse()
return {
  val, todos, addTodo,
  count,double,add,
  x,doubleX
}
Copy the code

script setup

The final return of the setup function is also centralized. If the number of lines is too large, it will also have a horizontal bar. This is easy to solve, because we can also separate todos into functions. So setup is all about the data source, very lean and silky

import useCounter from './counter'
import useMouse from './mouse'
import useTodo from './todos'
export default {
  setup(){
    let { val, todos, addTodo } = useTodo()
    let {count,double,add} = useCounter() 
    let {x, double:doubleX} = useMouse()
    return {
      val, todos, addTodo,
      count,double,add,
      x,doubleX
    }
  }
}
Copy the code

The setup script of VUe3 can be used to optimize the setup configuration and export one function at a time

<script setup>
import useCounter from './counter'
import useMouse from './mouse'
import useTodo from './todos'

let { val, todos, addTodo } = useTodo()
export {val, todos, addTodo}

let {count,double,add} = useCounter()
export {count,double,add}

let {x, double:doubleX} = useMouse()
export {x,doubleX}

</script>

Copy the code

See sfC-script-setup.md

Welcome to pay attention to me and big shuai *, you want him to write what article, give me a thumbs up message may be faster to get up early to read a book together


  • This is our team’s open source project Element3 welcome to try and star
  • A front-end component library that supports VUE3