Unexpectedly, Vue3's setup can still play like this

1, Foreword

Yesterday, I talked about the composite API, \ # it's almost 2202. Don't you know what the composite API of vue3 is? [2] Today, let's listen to what I can do with vue3's setup

Borrow a word from the official website

The setup option is a function that receives props and context

In other words, its basic writing should be like this

export default{
    name: 'test',
    setup(props,context){

     return {}   // Anything returned here can be used for the rest of the component
    }
    // "Remainder" of component
}
Copy code

Receive a props and context function and expose the contents of setup to the rest of the component through return.

2, setup considerations

  • Since the Created lifecycle method has not been executed when the setup function is executed, the variables and methods of data and methods cannot be used in the setup function
  • Since we cannot use data and methods in the setup function, Vue directly changed this in the setup function to undefined in order to avoid our wrong use

3, Define responsive data

ref reactive

vue3 uses ref reactive to define responsive data

Ref is used to define the basic data type as responsive data, which is essentially implemented by redefining properties based on Object.defineProperty() (ref is more suitable for defining basic data types)

reactive is used to define the reference type as responsive data. Its essence is to implement object Proxy based on Proxy

  • Basic data type (single type): except Object. String,Number,boolean,null,undefined.
  • Reference type: object. It contains function, Array and Date.

definition

<script>
import {ref, reactive} from "vue";
export default {
  name: "test",
  setup(){
    // Basic type
    const nub = ref(0)
    const str = ref('inline')
    const boo = ref(false)
    // reference type
    const obj = reactive({
      name:'inline',
      age:'18'
    })
    const arr = reactive(['0','1','2'])

    return{
      nub,
      str,
      boo,

      obj,
      arr,
    }
  }
}
</script>
Copy code

use

<template>
    <div>
      <h1>Basic type</h1>
      <p>nub:{{ nub }}</p>
      <p>str:{{ str }}</p>
      <p>boo:{{ boo }}</p>
    </div>
    <div>
      <h1>reference type</h1>
      <p>obj:{{ obj.name }}</p>
      <p>arr:{{ arr[1] }}</p>
    </div>
</template>
Copy code

result

4, toRefs

If we define responsive variables in the form of reactive

setup(){
  const obj = reactive({
    name:'inline',
    gender:'male',
    age:'18'
  })

  return{
    obj
  }
}
Copy code

use

<div>
  <p>full name:{{ obj.name }}</p>
  <p>Gender:{{ obj.gender }}</p>
  <p>Age:{{ obj.age }}</p>
</div>
Copy code

In this way, do we find it troublesome to use parameters in the template? Can we directly use {name}} to access it? The answer is feasible

Here we use the extension operator of es6

setup(){
  const obj = reactive({
    name:'inline',
    gender:'male',
    age:'18',
  })

  return{
    ...obj,
  }
}
Copy code

use

<div>
  <p>full name:{{ name }}</p>
  <p>Gender:{{ gender }}</p>
  <p>Age:{{ age }}</p>
</div>

<div>
  <button @click="name = 'juejin'">Change name</button>
  <button @click="gender = 'female'">Change gender</button>
  <button @click="age = '20'">Change age</button>
</div>
Copy code

result

Here we see that our parameters are normally displayed on the page, but when we change the parameters, we find that the view is not updated. Why???

We write the extension operator in its equivalent format

const obj = reactive({
    name:'inline',
    gender:'male',A
    age:'18',
  })
// ...obj ==> name:obj.name
 Copy code

Hey, wait, how can I be prompted when my mouse floats up that name is just a string?

Let's see what we prompt when we define the value with ref

Aoao, at this time, we see that name is a ref < string >, which is a responsive string.

In this way, we find the reason why the view is not updated. When we use the... Extension operator, we get only a common type of value, not a responsive data

To solve this problem, vue3 provides us with the toRefs function to see how it works

setup(){
  const obj = reactive({
    name:'inline',
    gender:'male',
    age:'18',
  })

  return{
    ...toRefs(obj),
  }
}
Copy code
<div>
  <p>full name:{{ name }}</p>
  <p>Gender:{{ gender }}</p>
  <p>Age:{{ age }}</p>
</div>

<div>
  <button @click="name = 'juejin'">Change name</button>
  <button @click="gender = 'female'">Change gender</button>
  <button @click="age = '20'">Change age</button>
</div>
Copy code

The parameters can be changed normally and changed successfully

toRefs summary

toRefs will transform a responsive object into an ordinary object, and then turn each attribute in the ordinary object into responsive data

5, Execute method in setup

Mode 1

Methods are defined in a way that reactive ly defines responsive data

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

export default {
  name: "test",
  setup(){
    const str = ref('inline')
    const fun = reactive({
      fun1(data){
        console.log(str.value)
        this.fun2(data)
      },
      fun2(data){
        console.log(data)
        console.log('I am fun2')
      }
    })

    return{
      ...toRefs(fun),
    }
  }
}
</script>
Copy code

Pass the value to fun1 by clicking the event, and fun1 will send it to fun2 after receiving it

Here, we use this.fun2() to call fun2. Why can this be executed normally without reporting undefind? Because this here is not that this, this in Vue2 is an instance, and this here is an object

<button @click="fun1('Hello')">Point me 1</button>
Copy code

As a result, it is successfully called and output

Mode II

Note that the method of calling fun2 here is different from method 1. You can call it directly instead of this

export default {
  name: "test",
  setup(){
      const fun1 = (data) => {
        fun2(data)
      }
      const fun2 = (data) => {
        console.log(data)
      }
    return{
      fun1,
    }
  }
}
Copy code

call

<button @click="fun1('Hello inline')">Point me 1</button>
Copy code

result

Mode III

This method avoids the problem of stacking function logic in setup. We can write independent functions as separate functions

Here, I write two function functions of fun() login() outside setup and call them respectively in setup

import {ref, reactive,toRefs} from "vue";

export default {
  name: "test",
  setup(){
    const test1 = fun()      // If the function returns too many parameters, it can be assigned to variables and exposed to the rest of the component with extension operators
    const { test } = login() // It can also be received individually
    return{
      ...toRefs(test1),
      test,
    }
  }
}

// Function 1
function fun(){
  let str = ref('I'm function 1')
  function fun1(data){
    console.log(str.value)
    fun2(data)
  }
  function fun2(data){
    console.log(data)
  }
  return{
    fun1,
    fun2,
  }
}

// Function 2
function login() {
  const obj = reactive({
    msg:'I'm feature 2. I love nuggets'
  })
  function test() {
    console.log(obj.msg)
  }
  return{
    test
  }
}
</script>
Copy code

call

<button @click="fun1('Hello inline')">Point me 1</button>
<button @click="test">Point me 2</button>
Copy code

result

Mode 4

It is the same as mode 3, except that we extract the two function functions and put them in a separate. js file

Then introduce the component and call it in setup

<template>
  <div style="text-align: center;margin-top: 50px">
    <button @click="fun1('Hello inline')">Point me 1</button>
    <button @click="test">Point me 2</button>
  </div>
</template>

<script>
import {ref, reactive,toRefs} from "vue";
import { fun,login } from './test.js'
export default {
  name: "test",
  setup(){
    const test1 = fun()
    const { test } = login()
    return{
      ...toRefs(test1),
      test,
    }
  }
}

</script>
Copy code

Normal execution and input

Mode 5

We can also write like this. Here, I define a reactive response object and assign it to the login variable. This response object contains the parameters, validation and methods we need to log in. Here, we put them all in the login response object and expose them with toRefs and extended operators

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

export default {
  name: "test",
  setup(){
    const login = reactive({
      param: {
        username: '123',
        password: '123456',
      },
      rules: {
        username: [{ required: true, message: 'enter one user name', trigger: 'blur' }],
        password: [{ required: true, message: 'Please input a password', trigger: 'blur' }],
      },
      login(){
        this.param.username = 'inline'
        this.param.password = '123456'
        console.log('Login successfully!')
      }
    })

    return{
      ...toRefs(login),
    }
  }
}
</script>
Copy code

Let's use it

<input type="text" v-model="param.username">
<input type="password" v-model="param.password">
<button @click="login">Sign in</button>
Copy code

Normal execution, so we can also write all methods and related parameters of a function in a reactive object

If there is any missing implementation method, please point it out in the comment area~~~

6, script setup

script setup has been officially released on vue3.2

usage

<script setup>

</script>
Copy code

Is it unusually simple

Variable methods do not require return

When < script setup > is used, the template is compiled into a rendering function inline within the scope of the setup function. This means that any internally declared top-level binding < script setup > can be used directly in the template

<script setup>
  const msg = 'Hello!'
</script>

<template>
  <div>{{ msg }}</div>
</template>
Copy code

The variables and methods defined in script setup do not need to be returned and can be used directly

Component introduction

The imported components can be used directly without registration

<script setup>
  // Imported components can also be used directly in the template
  import Foo from './Foo.vue'
  import { ref } from 'vue'

  // Write composite API code as in normal settings
  // You don't need to return everything manually
  const count = ref(0)
  const inc = () => {
    count.value++
  }
</script>

<template>
  <Foo :count="count" @click="inc" />
</template>
Copy code

Publish Props and Emits

<script setup>

  const props = defineProps({
    foo: String
  })
  
  const emit = defineEmits(['update', 'delete'])
</script>
Copy code

Normal script and script setup

script setup can exist at the same time as script

<script>
  export const name = 1
</script>

<script setup>
  import { ref } from 'vue'

  const count = ref(0)
</script>
Copy code

script setup additional options

script setup gives us most of the capabilities equivalent to the options api That is to say, script setup can do most of the things that options api can do

What else can script setup not do? As follows:

  • name
  • inheritAttrs
  • Custom options required for plug-ins or libraries

What if I want to use these? The answer is to write separately

<script>
  export default {
    name: 'CustomName',
    inheritAttrs: false,
    customOptions: {}
  }
</script>

<script setup>
  // script setup logic
</script>
Copy code

defineExpose

The variables defined by script setup will not be exposed by default, because the variables are contained in the closure of setup at this time. At this time, we can use define expose ({}) to expose the internal properties of the component to the parent component

<script setup>
  const a = 1
  const b = ref(2)

  defineExpose({
    a,
    b
  })
</script>
Copy code

When the parent component obtains the instance of this component through the template reference, the retrieved instance will be like this {a: number, b: number} (the reference will expand automatically as on ordinary instances)

7, Write at the end

There are many things script setup can say. When I understand it these days, I can issue a separate issue of its usage.

Finally, thank you for reading ~ ~ ~ your praise and reading are my greatest encouragement~~~

Author: inline705

https://juejin.cn/post/7029339447078420493

Posted by shilpa_agarwal on Mon, 29 Nov 2021 10:12:41 -0800