Composition API

一、Composition API

Composition API仅仅是vue3中新增的API,我们仍然可以使用options API
https://v3.cn.vuejs.org/guide/composition-api-introduction.html
setup 是composition API的入口
setup需要返回一个对象,返回的对象可以使用在模板、methods、computed以及生命周期的钩子函数中
setup是在props被解析完毕,但是在组件实例被创建之前执行的,所以setup内部无法通过this获取到组件的实例,因为组件实例还未被创建。所以在setup中也无法访问到组件中的data、computed、methods
setup 有两个参数:

  • props: 组件参数。用来接收外部传入的参数
    • props是响应式的对象,不能被结构。不要进行结构,结构后的数据就不是响应式的了。
    • watchEffect 和 watch 会监听和响应props的更新。
  • context:上下文对象,可进行结构其中包含以下属性
    • attrs
    • emit
    • slots
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app">
    x: {
     {
      x }} <br>
    y: {
     {
      y }}
  </div>
  <script type="module">
     // reactive 将来一个对象转换成响应式对象,并且该对象的嵌套属性也都会转换成响应式对象,返回的是proxy对象
    // 这里不使用observeable作为函数的名称是为了避免和另一个函数库rxjs重名出现混淆
    //  createApp 用来创建vue对象
    import {
      createApp, reactive } from './node_modules/vue/dist/vue.esm-browser.js'

    const app = createApp({
     
     /**
	   * setup返回一个对象,这个对象的所有属性会被到当前组件模板
	   * 它有两个参数,
	   * 第一个是 props
	   * 第二个是 content 上下文对象(attrs,emit,slots)
	   * 注意 props 对象是响应式的,watchEffect 或 watch 会观察和响应 props 的更新:
	   * 然而不要解构 props 对象,那样会使其失去响应性:
	   */
	      setup () {
      // 是composition API的入口
	        // const position = useMousePosition()
	        const {
      x, y } = useMousePosition()
	        return {
     
	          x,
	          y
	        }
	      }
	    })
    console.log(app)

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

二、生命周期钩子函数

Composition API_第1张图片
setup中也可以使用生命周期钩子函数,但是前面需要加上on然后首字母大写

setup 是在组件初始化之前执行的,是在beforeCreate和created之间执行的
unmounted类似之前的destroyed
下面两个都是在render函数被重新调用时触发
renderTracked 首次调用render的时候也会触发
renderTriggered 首次调用render的时候不会触发

 import {
      createApp, reactive, onMounted, onUnmounted} 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 position
    }

    const app = createApp({
     
      setup () {
      // 是composition API的入口
        const position = useMousePosition()
        return {
     
          position
        }
      }
    })
    console.log(app)
    app.mount('#app')

三、reactive-toRefs-ref

这三个函数都是创建响应式数据的

1、reactive

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app">
    x: {
     {
      x }} <br>
    y: {
     {
      y }}
  </div>
  <script type="module">
    // reactive 将来一个对象转换成响应式对象,并且该对象的嵌套属性也都会转换成响应式对象,返回的是proxy对象
    // 这里不使用observeable作为函数的名称是为了避免和另一个函数库rxjs重名出现混淆
    //  createApp 用来创建vue对象
    // toRefs 可以把一个响应式对象的所有属性也转换成响应式的 
    import {
      createApp, reactive, onMounted, onUnmounted, toRefs } from './node_modules/vue/dist/vue.esm-browser.js'

    function useMousePosition () {
     
      // 第一个参数 props
      // 第二个参数 context,attrs、emit、slots
     
      // reactive 把传入的对象包装成了proxy对象,将来访问position的x和y的时候,会调用代理对象的
      // getter 拦截手机依赖,当x和y变化之后会调用代理对象的setter进行拦截触发更新
      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 () {
      // 是composition API的入口
        // const position = useMousePosition()
        // 当把代理对象解构的时候,就相当于定义了x和y两个变量,来接收position.x和position.y
        // 而基本类型的赋值就是把值在内存中复制一份。所以这里的x y就是两个基本类型的变量,跟代理对象无关

        const {
      x, y } = useMousePosition()
        return {
     
          x,
          y
        }
      }
    })
    console.log(app)

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

2、toRefs函数

作用:把对象的每一个属性都转成响应式数据
内部实现原理:
toRefs要求传入的参数必须是代理对象
内部会创建一个新的对象,遍历传入的代理对象的所有属性,把所有属性的值都转换成响应式对象,然后再挂载到新创建的对象上,最后把新创建的对象返回。
它内部会为代理对象的每一个属性创建一个具有value属性的对象,该对象是响应式的。value属性具有getter和setter,这一点和ref函数类似。getter里返回代理对象中对象属性的值。setter中给代理对象属性赋值。所以返回的每一个属性都是响应式的

3、ref函数

作用:把普通数据转换成响应式数据

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <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 () {
     
      // 调用ref 返回的是一个对象,对象中只有一个属性value,这个value的值就是0,并且这个value属性是有
      // getter和setter的
      const count = ref(0) // 基本类型数据转换成响应式对象
      return {
     
        count,
        increase: () => {
     
          count.value++
        }
      }
    }

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

ref参数如果是对象的话,内部会调用reactive返回一个代理对象

四、computed

作用,简化模板中的代码,缓存计算的结果,数据变化时才会重新计算
两种用法
1、watch(()=>count.value+1)
传入一个获取值的函数,函数内部依赖响应式的数据,当依赖的数据发生变化后会重新执行该函数获取数据。
computed函数返回一个不可变的响应式对象,类似于使用ref创建的对象,只有一个value属性。获取计算属性的值要通过value属性来获取。模板中使用计算属性可以使用value

2、传入一个对象,该对象具有getter和setter,返回一个不可变得响应式对象

const count = ref(1)
const plusOne = computed({
     
 get: () => count.value + 1,
 set: val => {
     
 	count.value = val - 1
 }
})
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <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>
</body>
</html>

五、watch

watch3个参数

  • 第一个参数是侦听的数据源(一个拥有返回值的getter函数,也可以是ref)。
  • 第二个参数是数据变化处理函数。
  • 第三个参数是侦听选项,deep(深度监听)和 immediate(立即执行函数)。
    watch 返回一个函数,用来取消监听。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <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>
</body>
</html>

六、watchEffect

  • 是watch函数的简化版本,也用来监视数据的变化
  • 接收一个函数作为参数,监听函数内响应式数据的变化
    watchEffect其内部的代码和watch是一样的,不同的是,watchEffect它会立即执行,并且他会侦听setup中所有的发生变化的数据(不管数据源是否是响应式的),watchEffect和watch一样,它的返回值也是一个函数,用来停止侦听。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <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>
</body>
</html>

关于watchEffect更多的信息,查看官方文档:https://composition-api.vuejs.org/zh/api.html#watcheffect

你可能感兴趣的:(笔记,vue)