zoukankan      html  css  js  c++  java
  • 组合式API记录

    插件安装 及 注入

    # 安装插件
    npm install @vue/composition-api  
    yarn add @vue/composition-api
    
    # 在 main.js 文件中导入并注册使用
    import VueCompositionApi from '@vue/composition-api';
    Vue.use(VueCompositionApi);
    

    setup 介绍 及 基础使用

    setup 函数是一个新的组件选项,作为在组件内使用 Composition API 的入口
    创建组件实例,然后初始化 props,紧接着就调用 setup 函数。
    setup 返回一个对象,暴露给模板使用,对象的属性将会被合并到组件模板的渲染上下文
    注意:setup 返回的 ref 在模板种会自动解开,不需要写 .value

    <script>
    <template>
    	<div>
    		{{ count }} - {{ object.foo }}
    	</div>
    </template>
    // 引入插件
    import { ref, reactive } from '@vue/composition-api'
    
    export default {
    	setup() {
    		const count = ref(0)
    		const object = reactive({ foo: 'bar' })
    		// 暴露给模板使用
    		return {
    			count,
    			object
    		}
    	}
    }
    </script>
    

    参数 props

    setup 函数接收 props 作为第一个参数,props 对象是响应式的,watchEffect 或 watch 会观察和响应 props 的更新。
    注意:

    1. 不能在 setup 函数的形参内解构 props 对象,否则会失去响应性
    2. 在开发过程种,props 对象的值是不能改变的,否则会触发警告
    <script>
    export default {
    	props: {
    		name: String
    	},
    	// 注意:不能在直接解构第一个参数,可以在函数内部进行解构
    	setup(props) {
    		watchEffect(() => {
    			console.log(props.name)
    		})
    	}
    }
    </script>
    

    setup 函数第二个参数 context 上下文对象

    setup 函数的第二个参数是一个上下文对象,注意:在 setup() 函数种无法访问到 this

    export default {
    	setup(props, context) {
    		// 注意,context 可以在行上进行结构, 也可以在函数内进行结构  
    		const { root, emit, refs, attrs, slots, parent } = context
    	}
    }
    

    使用 defineComponent 使 setup() 参数获得类型推断的传递

    export default defineComponent({
    	name: '组件名称',
    	props: {}
    	setup(props, { root, emit, refs }) {
    		return {}
    	}
    })
    

    响应式系统 API - reactive

    import { reactive } from '@vue/composition-api'
    
    export default {
    	setup(props, context) {
    		// 创建响应式数据对象
    		const state = reactive({ count: 0 })
    		
    		// 返回响应式对象,提供给 template 使用
    		// 模板使用方式, <p> state.count: {{state.count}} </p> 
    		return state
    	}
    }
    

    响应式系统 API - ref

    ref() 函数用来根据给定的值创建一个响应式的数据对象,返回值是一个对象,这个对象上只包含一个 .value 属性

    import { ref } from '@vue/composition-api'
    
    export default {
    	setup(props, context) {
    		// 创建响应式数据
    		const count = ref(0) // 数字类型
    		// 在setup 内部使用时候,使用.vaue 进行访问更改 count.value = 100
    		const strVal = ref('default') // 字符串
    		// strVal.value = 'update'
    		const arrVal = ref(['小明', '小米']) // 数组
    		// arrVal.value = ['新东西', '新世界']
    		const objVal = ref({
    			num: 10, title: '结算'
    		})
    		// objVal.value.name = 100; objVal.value.title = '合计'
    		
    		# 在reactive 对象种访问 ref创建的响应式数据
    		# ref挂载到reactive上时,会自动把响应式数据根据对象展开为原始的值, 不需要通过 .value 就可以直接被访问  
    		const state = reactive({ count })
    		console.log(state.count) // 输出 0
    		state.count++   // 不需要通过 .value 就能直接访问原始值 
    		console.log(count) // 输出 1
    		
    		return {
    			count
    		}
    	}
    }
    

    isRef

    # 检查某个值是否 ref() 创建出来的对象。
    import { isRef } from '@vue/composition-api'
    const unerapped = isRef(foo) ? foo.value : foo
    

    toRefs

    toRefs() 函数可以将 reactive() 创建出来的响应式对象,转换为普通的对象,只不过,这个对象上的每个属性节点,都是 ref() 类型的响应式数据

    import { toRefs } from '@vue/composition-api'
    
    export default {
    	setup(props, context) {
    		// 定义响应式数据 对象
    		const state = reactive({
    			count: 0
    		})
    		
    		return {
    			// 将 state 上的每一个属性,都转化为 ref 形式的响应式数据  
    			...toRefs(state)
    		}
    	}
    }
    

    计算属性 computed

    computed() 用来创建计算属性,函数返回值是一个 ref 的实例

    const count = ref(1)
    # 1. 创建只读的计算属性
    // 根据 count 的值,创建一个响应式的计算属性 setOne
    // 根据依赖的 ref 自动计算并返回新的 ref
    const setOne = computed(() => count.value + 1)
    console.log( setOne.value ) // 输出 2
    setOne.value++   // 报错, 计算属性不能直接修改
    
    # 2. 创建可读可写的计算属性  
    // 在调用 computed() 函数期间, 传入一个包含 get 和 set 函数的对象. 可以得到一个可读写的计算属性  
    const setTwo = computed({
    	// 取值函数
    	get: () => count.value + 1,
    	// 赋值函数
    	set: val => {
    		count.value = val - 1
    	}
    })
    
    // 为计算属性赋值的操作,会触发 set 函数
    setTwo.value = 100 
    console.log( count.value ) // 99, 触发set后, count的值会被更新
    

    watch 监听

    可以实现在一个属性变更的时候,去执行我们想要的行为。
    比如:

    1. 当ID改变的时候,从数据库里面获取新的数据
    2. 当属性变换的时候执行一个动画
    3. 当搜索条件变更的时候,更新查询到的数据
    const state = reactive({ count: 0, title: 'xiaoming' })
    const count = ref(0)
    const title = ref('xiaoming')
    # 监听指定的数据源  
    watch(
    	() => state.count, // 监听 reactive 类型的数据源
    	count, // 监听 ref 类型的数据源
    	(val, oldVal) => {
    		/* ... */
    	}
    )
    
    # 监听多个数据源 ------
    watch(
    	// 监听 reactive 类型的数据源
    	[() => state.count, () => state.title], 
    	// 监听 ref 类型的数据源
    	[count, title],  
    	([count, title], [oldCount, oldTitle]) => {
    		console.log(count) // 新的 count 值
    		console.log(title) // 新的 title 值
    		console.log('-----------')
    		console.log(oldCount) // 旧的 count 值
    		console.log(oldTitle) // 旧的 title 值
    	},
    	{
    		lazy: true // 在 watch 被创建的时候,不执行回调函数中的代码
    	}
    )
    
    # 清除监听  
    // 在 setup 含税内创建的 watch 监听,会在当前组件被销毁的时候自动停止。 如果想要明确地停止某个监听, 可以调用 watch 函数的返回值即可  
    // 创建监听,并得到 停止函数
    const stopWatch = watch(() => {})
    // 调用停止函数,清除对应的监听
    stopWatch()
    
    # 在 watch 中清除无效的异步任务  
    // 有时候,当被 watch 监听的值发生变化时,或 watch 本身被 stop 之后,我们期望能够清除哪些无效的异步任务,此时,watch 回调函数中提供了一个 cleanup registrator function 函数来执行清除的工作。这个清除函数会在如下情况下被调用: 1. watch 被重复执行了 2. watch 被强制 stop 了 
    const keyVal = ref('')
    // 异步任务
    const asyncPrint = val => {
    	return setTimeout(() => {
    		console.log(val)
    	}, 1000)
    }
    
    watch(keyVal, (val, oldVal, onCleanup) => {
    	// 执行异步任务,并得到关闭异步任务的 函数
    	const timeId = asyncPring(val)
    	
    	// 如果 watch 监听被重复执行了,则会先清除上次未完成的异步任务
    	onCleanup(() => clearTimeout(timeId))
    }, {
    	lazy: true // watch 刚被创建的时候不执行
    })
    

    watchEffect 特点 及 原理

    1. 不需要指定监听的属性,会自动收集依赖,只要我们在回调中引用到了响应式的属性,那么当这些属性变更的时候,回调都会执行。而 watch 只能监听指定的属性而做出变更
    2. watch 可以获取到新值和旧值(更新前的值), 而watchEffect 是拿不到的
    3. watchEffect 如果存在的话,在组件初始化的时候就会执行一次用来收集依赖(与computed同理), 而后收集的依赖发生变化,这个回调才会再次执行,而watch不需要,因为一开始就指定了依赖。
    import { watchEffect, ref } from 'vue'
    setup () {
    	const userID = ref(0)
    	watchEffect(() => console.log(userID))
    	setTimeout(() => {
    		userID.value = 1
    	}, 1000)
    	
    	return { userID }
    }
    

    停止监听

    watchEffect 会返回一个用于停止这个监听的函数
    如果 watchEffect 是在 setup 或者 生命周期里面注册的话,在组件取消挂载的时候会自动的停止掉

    const stop = watchEffect(() => {
    	// ...
    })
    stop()
    

    新版本的生命周期函数 - 且只能在 setup 函数中使用

    import { onMounted, onUpdated, onUnmounted } from '@vue/composition-api' 
    
    export default {
    	setup(props, context) {
    		onMounted(() => {
    			console.log('mounted')
    		})
    		onUpdated(() => {
    			console.log('updated')
    		})
    		onUnmounted(() => {
    			console.log('unmounted')
    		})
    	}
    }
    

    模板 refs

    通过 ref() 还可以引用页面上的元素或组件

    <template>
    <div>
    	<h1 ref="titleRef">通过ref() 函数来引用元素</h1>
    </div>
    </template>
    <script>
    import { ref, onMounted } from '@vue/composition-api'
    export default {
    	setup() {
    		// 创建一个 DOM 引用
    		const titleRef = ref(null)
    		
    		// 在 DOM 首次加载完毕之后,才能获取到元素的引用
    		onMounted(() => {
    			// titleRef.value 是原生DOM对象
    			titleRef.value.style.color = 'red'
    		})
    		return {
    			titleRef
    		}
    	}
    }
    </script>
    

    createComponent

    这个函数不是必须的,除非你想要完美结合 TypeScript 提供的类型推断来进行项目的开发。
    函数仅仅提供了类型推断,方便在结合 TypeScript 书写代码时,能为 setup 中的 props 提供完整的类型推断

    import { createComponent } from '@vue/composition-api'
    
    export default createComponent({
    	props: {
    		foo: String
    	},
    	setup(props, context) {
    		props.foo // type: string
    	}
    })
    

    学习资源地址

    1. 组合式API
    2. vue3.x新特性
  • 相关阅读:
    VS2013+PTVS,python编码问题
    关于网易云音乐爬虫的api接口?
    Django分页和查询参数的问题
    angular route 与 django urls 冲突怎么解决?
    200 from memory cache / from disk cache / 304 Not Modified 区别
    go语言中在变量后加上接口是什么意思?
    append生成新变量的时候,没有如预期(It's a feature,not a bug?)
    为一个支持GPRS的硬件设备搭建一台高并发服务器用什么开发比较容易?
    学golang之前都需要哪些前置知识?
    求推荐go语言开发工具及go语言应该以哪种目录结构组织代码?
  • 原文地址:https://www.cnblogs.com/yuxi2018/p/14160875.html
Copyright © 2011-2022 走看看