ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Vue3 setup详解

2022-03-20 12:37:10  阅读:178  来源: 互联网

标签:const 对象 setup value reactive 详解 Vue3 ref


setup执行的时机

  1. 在beforeCreate之前执行(一次),此时组件对象还没创建;
  2. this是undefined,不能通过this来访问data/computed/methods/props;
  3. 其实所有的composition API相关回调函数中也都不可以;

setup的返回值

  1. 一般都返回一个对象:为模板提供数据,也就是模板中可以直接使用此对象中的所有属性/方法
  2. 返回对象中的属性会与data函数返回对象合并成为组件对象的属性
  3. 返回对象中的方法会与methods中的方法合并成功组件对象的方法
  4. 如果有重名,setup优先
  5. 注意:一般不要混合使用:methods中可以访问setup提供的属性和方法,但在setup方法中不能访问data和methods;setup不能是async函数:因为返回值不再是return的对象,而不是promise,模板看不到return对象中的属性数据

setup参数

  1. setup(props,context)/setup(props,{attrs,slots,emit})
  2. props:包含props配置声明且传入了所有属性的对象
  3. attrs:包含没有在props配置中声明的属性的对象,相当于this.$attrs
  4. slots:包含所有传入的插槽内容的对象,相当于this.$slots
  5. emit:用来分发自定义事件的函数,相当于this.$emit

演示代码

  1. 父组件
	<template>
  		<h2>App</h2>
  		<p>msg: {{msg}}</p>
  		<button @click="fn('--')">更新</button>
		<child :msg="msg" msg2="cba" @fn="fn"/>
	</template>
	<script lang="ts">
		import {
  			reactive,
  			ref,
		} from 'vue'
		import child from './child.vue'

		export default {
  			components: {
    			child
  			},

  			setup () {
    			const msg = ref('abc')
    			function fn (content: string) {
      			msg.value += content
    		}
    		return {
      			msg,
      			fn
    		}
  		}
	}
</script>
  1. 子组件
<template>
  <div>
    <h3>{{n}}</h3>
    <h3>{{m}}</h3>
	<h3>msg: {{msg}}</h3>
    <h3>msg2: {{$attrs.msg2}}</h3>
    <slot name="xxx"></slot>
    <button @click="update">更新</button>
  </div>
</template>
<script lang="ts">
	import {
  		ref,
  		defineComponent
	} from 'vue'

	export default defineComponent({
  		name: 'child',
	  	props: ['msg'],
  		emits: ['fn'], // 可选的, 声明了更利于程序员阅读, 且可以对分发的事件数据进行校验
  		data () {
    		console.log('data', this)
    		return {
      			// n: 1
    	}
  	},

  	beforeCreate () {
    	console.log('beforeCreate', this)
  	},

  	methods: {
    	// update () {
    	//   this.n++
    	//   this.m++
    // }
  },

  // setup (props, context) {
  setup (props, {attrs, emit, slots}) {
    console.log('setup', this)
    console.log(props.msg, attrs.msg2, slots, emit)

    const m = ref(2)
    const n = ref(3)

    function update () {
      // console.log('--', this)
      // this.n += 2 
      // this.m += 2
      m.value += 2
      n.value += 2

      // 分发自定义事件
      emit('fn', '++')
    }

    return {
      m,
      n,
      update,
    }
  },
})
</script>

reactive与ref细节

  1. 是vue3的composition API中最重要的响应式API
  2. ref用来处理基本类型的数据,reactive用来处理对象(递归深度响应式)
  3. 如果用ref对象/数组,内部会自动将对象/数组转换为reactive的代理对象
  4. ref内部:通过给value属性添加getter/setter来实现对数据的劫持
  5. reactive内部:通过使用Proxy来实现对对象内部所有数据的劫持,并通过Reflect操作对象内部数据
  6. ref的数据操作:在js中要.value,在模板中不需要(内部解析模板时会自动添加.value)
<template>
  <h2>App</h2>
  <p>m1: {{m1}}</p>
  <p>m2: {{m2}}</p>
  <p>m3: {{m3}}</p>
  <button @click="update">更新</button>
</template>
<script lang="ts">
import {
  reactive,
  ref
} from 'vue'

export default {

  setup () {
    const m1 = ref('abc')
    const m2 = reactive({x: 1, y: {z: 'abc'}})

    // 使用ref处理对象  ==> 对象会被自动reactive为proxy对象
    const m3 = ref({a1: 2, a2: {a3: 'abc'}})
    console.log(m1, m2, m3)
    console.log(m3.value.a2) // 也是一个proxy对象

    function update() {
      m1.value += '--'
      m2.x += 1
      m2.y.z += '++'

      m3.value = {a1: 3, a2: {a3: 'abc---'}}
      m3.value.a2.a3 += '==' // reactive对对象进行了深度数据劫持
      console.log(m3.value.a2)
    }

    return {
      m1,
      m2,
      m3,
      update
    }
  }
}
</script>

计算属性和监视属性

<template>
  <h2>App</h2>
  fistName: <input v-model="user.firstName"/><br>
  lastName: <input v-model="user.lastName"/><br>
  fullName1: <input v-model="fullName1"/><br>
  fullName2: <input v-model="fullName2"><br>
  fullName3: <input v-model="fullName3"><br>

</template>
<script lang="ts">
/*
计算属性与监视
1. computed函数: 
  与computed配置功能一致
  只有getter
  有getter和setter
2. watch函数
  与watch配置功能一致
  监视指定的一个或多个响应式数据, 一旦数据变化, 就自动执行监视回调
  默认初始时不执行回调, 但可以通过配置immediate为true, 来指定初始时立即执行第一次
  通过配置deep为true, 来指定深度监视
3. watchEffect函数
  不用直接指定要监视的数据, 回调函数中使用的哪些响应式数据就监视哪些响应式数据
  默认初始时就会执行第一次, 从而可以收集需要监视的数据
  监视数据发生变化时回调
*/

import {
  reactive,
  ref,
  computed,
  watch,
  watchEffect
} from 'vue'

export default {

  setup () {
    const user = reactive({
      firstName: 'A',
      lastName: 'B'
    })

    // 只有getter的计算属性
    const fullName1 = computed(() => {
      console.log('fullName1')
      return user.firstName + '-' + user.lastName
    })

    // 有getter与setter的计算属性
    const fullName2 = computed({
      get () {
        console.log('fullName2 get')
        return user.firstName + '-' + user.lastName
      },

      set (value: string) {
        console.log('fullName2 set')
        const names = value.split('-')
        user.firstName = names[0]
        user.lastName = names[1]
      }
    })

    const fullName3 = ref('')

    /* 
    watchEffect: 监视所有回调中使用的数据
    */
    /* 
    watchEffect(() => {
      console.log('watchEffect')
      fullName3.value = user.firstName + '-' + user.lastName
    }) 
    */

    /* 
    使用watch的2个特性:
      深度监视
      初始化立即执行
    */
    watch(user, () => {
      fullName3.value = user.firstName + '-' + user.lastName
    }, {
      immediate: true,  // 是否初始化立即执行一次, 默认是false
      deep: true, // 是否是深度监视, 默认是false
    })

    /* 
    watch一个数据
      默认在数据发生改变时执行回调
    */
    watch(fullName3, (value) => {
      console.log('watch')
      const names = value.split('-')
      user.firstName = names[0]
      user.lastName = names[1]
    })

    /* 
    watch多个数据: 
      使用数组来指定
      如果是ref对象, 直接指定
      如果是reactive对象中的属性,  必须通过函数来指定
    */
    watch([() => user.firstName, () => user.lastName, fullName3], (values) => {
      console.log('监视多个数据', values)
    })

    return {
      user,
      fullName1,
      fullName2,
      fullName3
    }
  }
}
</script>

生命周期

与2.x版本生命周期相对应的组合API
。beforeCreate=>使用setup()
。create=>使用setup()
。beforeMount=>onBeforeMount
。mounted=>onMounted
。beforeUpdate=>onBeforeUpdate
。updated=>onUpdated
。beforeDestroy=>onBeforeUnmount
。destroyed=>onUnmounted
。errorCaptured=>onErrorCaptured

toRefs

  1. 把一个响应式对象转换成普通对象,该普通对象的每个property都是一个ref
  2. 应用:当从合成函数返回响应式对象时,toRefs非常有用,这样消费组件就可以在不丢失响应式的情况下对返回的对象进行分解使用
  3. 问题:reactive对象取出的所有属性值都是非响应式的
  4. 解决:利用toRefs可以将一个响应式reactive对象的所有原始属性转换为响应式的ref属性
<template>
  <h2>App</h2>
  <h3>foo: {{foo}}</h3>
  <h3>bar: {{bar}}</h3>
  <h3>foo2: {{foo2}}</h3>
  <h3>bar2: {{bar2}}</h3>
</template>
<script lang="ts">
import { reactive, toRefs } from 'vue'
/*
toRefs:
  将响应式对象中所有属性包装为ref对象, 并返回包含这些ref对象的普通对象
  应用: 当从合成函数返回响应式对象时,toRefs 非常有用,
        这样消费组件就可以在不丢失响应式的情况下对返回的对象进行分解使用
*/
export default {

  setup () {

    const state = reactive({
      foo: 'a',
      bar: 'b',
    })

    const stateAsRefs = toRefs(state)

    setTimeout(() => {
      state.foo += '++'
      state.bar += '++'
    }, 2000);

    const {foo2, bar2} = useReatureX()

    return {
      // ...state,
      ...stateAsRefs,
      foo2, 
      bar2
    }
  },
}

function useReatureX() {
  const state = reactive({
    foo2: 'a',
    bar2: 'b',
  })

  setTimeout(() => {
    state.foo2 += '++'
    state.bar2 += '++'
  }, 2000);

  return toRefs(state)
}

</script>

ref获取元素

  1. 利用ref函数获取组件中的标签元素
  2. 功能需求:让输入框自动获取焦点
<script lang="ts">
import { onMounted, ref } from 'vue'
/* 
ref获取元素: 利用ref函数获取组件中的标签元素
功能需求: 让输入框自动获取焦点
*/
export default {
  setup() {
    const inputRef = ref<HTMLElement|null>(null)

    onMounted(() => {
      inputRef.value && inputRef.value.focus()
    })

    return {
      inputRef
    }
  },
}
</script>

标签:const,对象,setup,value,reactive,详解,Vue3,ref
来源: https://www.cnblogs.com/guozhiqiang/p/16029553.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有