亲爱的视频版

博客内容已经录制了对应视频,点击可跳转

入口函数-setup

现在我们已经知道 为什么要使用组合式 API 了 ,那么接下来我们需要看的就是如何使用 组合式 API。

在 vue 组件之中,我们通过 setup 函数来使用 组合式 API。

那么下面我们将分别从函数的:

  • 调用时机
  • this 指向
  • 函数参数
  • 返回值

这四个方面来解析 setup 函数

调用时机与 this 指向

setup 函数在创建组件之前被调用,所以在 setup 被执行时,组件实例并没有被创建

因此在 setup 函数中,我们将 没有办法 获取到 this 。

我们来看下面的这一段代码:

// 模板
<body>
  <div id="app">
    <component-b title="父组件传递过来的 title"></component-b>
  </div>
</body> 
// 配置对象
<script>
const component = {
    setup() {
      // 先于 created 执行,此时组件尚未创建,this 指向 window
      console.log(this); // window
    },
    created() {
      console.log(this); // proxy 对象 -> 组件实例
    }
  }

  // 1. 通过 createApp 方法创建根组件,返回根组件实例
  const app = Vue.createApp(component)
  // 2. 通过实例对象的 mount 方法进行挂载
  app.mount('#app')
</script>

函数参数

对于 setup 函数来说,它接收两个参数,分别为:

  • props
  • context

props

通过 prop 传递过来的所有数据,我们都可以在这里进行接收。并且获取到的数据将保持响应性

我们看下面的代码:

父组件:
// 模板
<body>
  <div id="app">
    <component-b title="父组件传递过来的 title"></component-b>
  </div>
</body>
// 配置对象
<script>
const component = {
    setup() {
        // 先于 created 执行,此时组件尚未创建,this 指向 window
        console.log(this); // window
    },
    created() {
        console.log(this); // proxy 对象 -> 组件实例
    },
    components: {
        componentB
    }
}
 // 1. 通过 createApp 方法创建根组件,返回根组件实例
 const app = Vue.createApp(component)
 // 2. 通过实例对象的 mount 方法进行挂载
 app.mount('#app')
</script>
子组件:
  const componentB = {
    props: {
      title: {
        type: String,
        required: true
      }
    },
    setup(props) {
      console.log(props); // Proxy {title: "父组件传递过来的 title"}
      console.log(props.title); // "父组件传递过来的 title"
    },
    template: `
      <div>{{title}}</div>
    `
  }

context

context 是一个 JavaScript 对象,这个对象暴露了三个组件的属性,我们可以通过 解构 的方式来分别获取这三个属性

 // setup(props, context) { 
 setup(props, { attrs, slots, emit }) {
      // Attribute (非响应式对象) 非 props 数据
      console.log(attrs)
      // 插槽 (非响应式对象)
      console.log(slots);
      // 触发事件 (方法) === this.$emit
      console.log(emit);
    }

attrs: 它是绑定到组件中的 非 props 数据,并且是非响应式的。

slots: 是组件的插槽,同样也不是 响应式的。

emit: 是一个方法,相当于 vue2 中的 this.$emit 方法。

然后我们通过下面的代码,来看一下这三个属性的实际使用:

// 父组件
<body>
  <div id="app">
    <component-b title="父组件传递过来的 title" desc="父组件传递过来的普通属性" @update="onUpdate">
      <h1>普通的匿名插槽</h1>
    </component-b>
  </div>
</body>
<script>
  const component = {
    methods: {
      onUpdate(desc) {
        console.log(desc); // 子组件更新的数据
      }
    },
    components: {
      componentB
    }
  }

  // 1. 通过 createApp 方法创建根组件,返回根组件实例
  const app = Vue.createApp(component)
  // 2. 通过实例对象的 mount 方法进行挂载
  app.mount('#app')
</script>
// 子组件
  const componentB = {
    props: {
      title: {
        type: String,
        required: true
      }
    },
    setup(props, { attrs, slots, emit }) {
      // Attribute (非响应式对象)
      console.log(attrs) // Proxy {desc: "父组件传递过来的普通属性", __vInternal: 1, onUpdate: ƒ}
      // 插槽 (非响应式对象)
      console.log(slots.default()); // [{__v_isVNode: true, __v_skip: true, type: "h1", …}]
      // 触发事件 (方法)
      // console.log(emit);
      emit('update', '子组件更新的数据') // 发出一个事件,在父组件中监听这个事件,并进行打印
    },
    template: `
      <div>{{title}}</div>
    `
  }

返回值

我们可以在 setup 函数中返回一个对象,这样我们就可以在模板中直接访问该对象中的属性和方法

   setup(props, { attrs, slots, emit }) {
      return {
        content: '这是 setup 中返回的数据',
        onLog: () => {
          console.log('调用 onLog 方法')
        }
      }
    },
    template: `
      <div>
        {{content}}
        <button @click="onLog">log</button>  
      </div>
    `

总结

那么我们最后总结一下 setup 函数的所有特性:

  • setup 函数是组合式 API 的入口函数,它在 组件创建之前 被调用
  • 因为在 setup 执行时组件尚未创建,setup 函数中的 this 不是当前组件的实例
  • 函数接收两个参数,props 和 context,context 可以解构为 attrs、slots、emit 函数
  • 函数可以返回一个对象,对象的属性可以直接在模板中进行使用,就像之前使用 data 和 methods 一样。
Logo

前往低代码交流专区

更多推荐