Part3-5-2 Composition API

Posted 沿着路走到底

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Part3-5-2 Composition API相关的知识,希望对你有一定的参考价值。

createApp

createApp 的作用是创建一个 vue 对象,它可以接收一个选项作为一个参数,也就是一个组件的选项,和vue2中给构造函数传入的选项一样,可以传入 data、methods、computed、created等选项。

data不支持对象的写法,data必须是函数。

<script type="module">
    import { createApp } from './node_modules/vue/dist/vue.esm-browser.js'

    const app = createApp({
      // setup 需要返回一个对象,可以使用在模板、methods、computed、以及生命周期的钩子函数中
      // setup执行的时机:props解析完毕,组件实例被创建之前执行。
      // 因此在 setup 内部,无法通过 this 获取到组件的实例,因为组件实例还未被创建。
      // setup 中的 this 此时指向 undefined
      setup () {
        // 第一个参数 props, props 的作用是用来接收外部传入的参数,props 是一个响应式的对象,但是不能被解构
        // 第二个参数 context,context 是一个对象,它具有三个成员:attrs、emit、slots
        
        const position = {
            x: 0,
            y: 0
        }

        return {
            position // 将来可以在模板以及组件的其他位置,使用这个对象,但此时并不是响应式对象
        }
      }
    })
    console.log(app)

    app.mount('#app')
  </script>

reactive

reactive 的作用是把一个对象转换成响应式对象,并且该对象的嵌套对象也都转换成响应式对象。

它返回的是一个 proxy 对象。

<script type="module">
    import { createApp, reactive } from './node_modules/vue/dist/vue.esm-browser.js'

    const app = createApp({
      setup () {
        // 使用 reactive 将对象转换成响应式对象
        const position = reactive({
            x: 0,
            y: 0
        })

        return {
            position
        }
      }
    })
    console.log(app)

    app.mount('#app')
  </script>

生命周期钩子函数

setup 是在 beforeCreate 和 created 之间执行的。

onRenderTracked 和 onRenderTriggered 在 render 函数被重新调用时触发。

onRenderTracked 在 render 函数首次调用时也会触发。

onRenderTriggered 在 render 函数首次调用时不会触发。

toRefs

const { x, y } = useMousePosition()

将 x,y 从 useMousePosition() 中解构出来,x,y 不是响应式数据。

这是因为 

const position = reactive({
        x: 0,
        y: 0
})

这里使用 reactive 将 position 包装成了 proxy 对象,当调用 position.x,position.y时,会调用代理中的 get 方法拦截并收集依赖。当 position.x,position.y 发生变化时,会调用 set 拦截并触发更新。

当把代理对象解构的时候,就相当于定义了x,y这两个变量来接收positon.x,position.y,而基本类型的赋值就是把值在内存中复制一份,所以这里的x,y只是2个基本类型的变量,和代理对象无关。

toRefs 可以把一个响应式对象中的属性也转换成响应式的。

toRefs 要求传入的参数必须是一个代理对象。

toRefs 原理:内部会创建一个新的对象,遍历传入的代理对象的所有属性,把所有属性的值都转换成响应式对象,

并且属性是一个对象,具有 value 属性,在模板中使用,可以将value省略,但是在代码中不能省略。

然后挂载到新创建的对象上,再将新创建的对象返回。

<div id="app">
    x: {{ x }} <br>
    y: {{ y }}
</div>
  
<script type="module">
    import { createApp, reactive, onMounted, onUnmounted, toRefs } from './node_modules/vue/dist/vue.esm-browser.js'

    function useMousePosition () {
      const position = reactive({
        x: 0,
        y: 0
      })

      const update = e => {
        position.x = e.pageX
        position.y = e.pageY
      }

      onMounted(() => {
        window.addEventListener('mousemove', update)
      })

      onUnmounted(() => {
        window.removeEventListener('mousemove', update)
      })

      return toRefs(position)
    }

    const app = createApp({
      setup () {
        // const position = useMousePosition()
        const { x, y } = useMousePosition()
        return {
          x,
          y
        }
      }
    })
    console.log(app)

    app.mount('#app')
  </script>

ref

ref的作用是将基本类型的数据包装成响应式对象。

而 reactive 是将一个对象转换成响应式数据。

如果 ref 传入的是对象时,内部会去调用 reactive 返回一个代理对象。

如果 ref 传入的是基本类型数据时,会创建一个只有 value 属性的对象。

<div id="app">
    <button @click="increase">按钮</button>
    <span>{{ count }}</span>
  </div>
  <script type="module">
    import { createApp, ref } from './node_modules/vue/dist/vue.esm-browser.js'
    
    function useCount () {
      const count = ref(0)
      return {
        count,
        increase: () => {
          count.value++
        }
      }
    }

    createApp({
      setup () {
        return {
          ...useCount()
        }        
      }
    }).mount('#app')
  </script>

computed

 

<div id="app">
    <button @click="push">按钮</button>
    未完成:{{ activeCount }}
  </div>
  <script type="module">
    import { createApp, reactive, computed } from './node_modules/vue/dist/vue.esm-browser.js'
    const data = [
      { text: '看书', completed: false },
      { text: '敲代码', completed: false },
      { text: '约会', completed: true }
    ]

    createApp({
      setup () {
        const todos = reactive(data)

        const activeCount = computed(() => {
          return todos.filter(item => !item.completed).length
        })

        return {
          activeCount,
          push: () => {
            todos.push({
              text: '开会',
              completed: false
            })
          }
        }
      }
    }).mount('#app')
  </script>

Watch

Watch  的三个参数:

  • 第一个参数:要监听的数据,可以是一个获取值的函数,监听这个函数返回值的变化、或者是一个ref, 或者是 reactive 返回的对象,或者是数组
  • 第二个参数:监听到数据变化后执行的函数,这个函数有两个参数分别是新值和旧值
  • 第三个参数;选项对象,deep 和 immediate

Watch 的返回值:

  • 取消监听的函数
<div id="app">
    <p>
      请问一个 yes/no 的问题:
      <input v-model="question">
    </p>
    <p>{{ answer }}</p>
  </div>

  <script type="module">
    // https://www.yesno.wtf/api
    import { createApp, ref, watch } from './node_modules/vue/dist/vue.esm-browser.js'

    createApp({
      setup () {
        const question = ref('')
        const answer = ref('')

        watch(question, async (newValue, oldValue) => {
          const response = await fetch('https://www.yesno.wtf/api')
          const data = await response.json()
          answer.value = data.answer
        })

        return {
          question,
          answer
        }
      }
    }).mount('#app')
  </script>

WatchEffect

  • 是 watch 函数的简化版本,也用来监视数据的变化,内部实现是和 Watch 调用的同一个函数,不同的是,watchEffect 没有第二个回调函数的参数,watchEffect 会接收一个 函数 作为参数,它会监听 函数内部响应式数据的变化,它会立即执行一次这个函数,当数据发生变化后,会重新运行该函数,返回一个取消监听的函数
  • 接收一个函数作为参数,监听函数内响应式数据的变化
<div id="app">
    <button @click="increase">increase</button>
    <button @click="stop">stop</button>
    <br>
    {{ count }}
  </div>

  <script type="module">
    import { createApp, ref, watchEffect } from './node_modules/vue/dist/vue.esm-browser.js'

    createApp({
      setup () {
        const count = ref(0)
        const stop = watchEffect(() => {
          console.log(count.value)
        })

        return {
          count,
          stop,
          increase: () => {
            count.value++
          }
        }
      }
    }).mount('#app')
  </script>

1

以上是关于Part3-5-2 Composition API的主要内容,如果未能解决你的问题,请参考以下文章

在 uni-app 中使用 composition-api 组合API开发

vue2 和 composition api - 无法导入 store,错误 [vue-composition-api] 在使用任何函数之前必须调用 Vue.use(VueCompositionAPI

vue3的composition-api实践总结

vue-composition-api 中的 Refs 方法

Composition API

Composition API