Composition API

Composition API


Composition API也称为组合式API,实现代码的共享以及重用

Vue3.0 暴露变量必须 return 出来,template中才能使用;

Vue3.2 中 只需要在 script 标签上加上 setup 属性,组件在编译的过程中代码运行的上下文是在 setup() 函数中,无需return,template可直接使用


Composition-api提供的函数


setup

新的 setup 组件选项在创建组件之前执行,一旦 props 被解析,并充当合成 API 的入口点

由于在执行 setup 时尚未创建组件实例,因此在 setup 选项中没有 this。

这意味着,除了props 之外,将无法访问组件中声明的任何属性——本地状态、计算属性或方法。


setup()接收两个参数 propscontext

props是响应的 当传入的props更新时会同步更新

但是因为 props 是响应式的,所以不能使用 ES6 解构,因为它会消除 prop 的响应性。

如果需要解构 prop,可以通过使用 setup 函数中的 toRefs 来安全地完成

export default {
  props: {
    title: String
  },
  setup(props) {
    console.log(props.title)
  }
}

context暴露三个属性

export default {
  setup(props, context) {
    // Attribute (非响应式对象)
    // 可以读取所有除了在props当中声明的自定属性以外传递的 自定义属性的值 this.$attrs
    // 即所有从父组件传递过来的属性 除去使用props中声明过的
    console.log(context.attrs)

    // 插槽 (非响应式对象)
    console.log(context.slots)

    // 触发事件 (方法)
    // 用于触发绑定的自定义事件 this.$emit
    console.log(context.emit)
  }
}

执行 setup 时组件实例尚未被创建。因此只能访问props,attrs,slots,emit属性



ref

用来定义响应式的 字符串、 数值、 数组、Bool类型

对于ref对象而言,读写它的值都需要通过它的value属性

但在模板中使用时不需要.value属性,模板会自行的对于它的结构进行解包

export default {
    data() {
        return {
        }
    },
    setup() {
        let msg = ref("这是setup中的msg");
        let list = ref(["1", "2", "3"])
        let updateMsg = () => {
            alert("触发方法");
            msg.value = "改变后的值"
        }
        return {
            msg,
            list,
            updateMsg
        }
    },
}



reactive

用来定义响应式的对象

export default {
    data() {
        return {
        }
    },
    setup() {
        let msg = ref("这是setup中的msg");
        let setupData = reactive({
            title: "reactive定义响应式数据的title",
            userinfo: {
                username: "张三",
                age: 20
            }
        })
        let updateMsg = () => {
            alert("触发方法");
            msg.value = "改变后的值"
        }
        let updateTitle = () => {
            alert("触发方法");
            setupData.title = "我是改变后的title"
        }
        return {
            msg,
            setupData,
            updateMsg,
            updateTitle
        }
    },
}

要改变ref定义的属性名称需要通过 属性名称.value来修改

要改变reactive中定义的对象名称可以直接修改


watchEffect

在响应式地跟踪其依赖项时立即运行一个函数,并在更改依赖项时重新运行它。

与侦听器watch类似 不过在组件创建时会默认执行一次

export default {
    name: "WatchEffect",
    setup() {
        const data = reactive({
            count: 1,
            num: 1
        });
        const stop = watchEffect(() => console.log(`侦听器:${data.count}`));
        	// data.count变化时才会执行
        setInterval(() => {
            data.count++;
        }, 1000);
        return {
            data,
            stop
        };
    },
};



watch

与原先的侦听器类似,接收三个参数,第一个时要监听的状态,第二个是处理函数,第三个是配置项

对比watchEffect,watch允许我们:

懒执行,也就是说仅在侦听的源变更时才执行回调;

更明确哪些状态的改变会触发侦听器重新运行;

访问侦听状态变化前后的值

export default {
    name: "Watch",
    setup() {
    	const a = ref('cc')
        const data = reactive({
            count1: 0,
            count2: 0
        });
        
        // 侦听单个数据源
        // 不能直接侦听data.count1
        let stop1 = watch(data, () =>
            console.log("watch1", data.count1, data.count2)
        );
		
		// 如果需要监听data.count1 则需要函数返回值的形式
		stop1 = watch(() => data.count1, (value, oldValue, onCleanup) =>
            console.log("watch1", data.count1, data.count2)
        );

		// 监听ref属性且进行配置
        watch(a, (value, oldValue, onCleanup) => {
		  console.log(d.value)
		}, {
		  immediate: true
		})
        
        // 侦听多个数据源
        let stop2 = watch([data], () => {
            console.log("watch2", data.count1, data.count2);
        });
        
		// 同样需要监听多个对象的值时也需要函数返回值
		// 当监听多个数据组成的数组时,在第二个参数的回调函数的参数中对应接收多个数组 每一个对应一个监听的值
		stop2 = watch(() => [data.count1, data.count2], ([newCount1, oldCount1], [newCount2, oldCount2]) => {
            console.log("watch2", data.count1, data.count2);
        });

		setInterval(() => {
            data.count1++;
        }, 1000);
        
        return {
            data,
            stopAll: () => {
                stop1();
                stop2();
            },
        };
    },
};

当需要停止对数据的监听时,调用watch的返回值即可

stop()
stop2()

// 当我们使用watch回调无法停止监听时也可以通过设置flag实现



无论watch还是watchEffect,在回调函数中获取dom元素都是更新前的,如果要获取更新后的dom,需要设置配置项flush: 'post'

watch(source, callback, {
  flush: 'post'
})
watchEffect(callback, {
  flush: 'post'
})

// 或者直接使用vue3新增的另一个hooks
watchPostEffect(() => {
  /* 在 Vue 更新后执行 */
})



computed

与原先的计算属性相同

export default {
    name: "解构响应式对象数据",
    setup() {
        const user = reactive({
            firstName: "",
            lastName: "",
        });
        const fullName = computed(() => {
            return user.firstName + " " + user.lastName
        })
        return {
            ...toRefs(user),
            fullName
        };
    },
};



toRefs

解构响应式对象数据而不丢失响应性

响应式对象数据如果通过es6…运算符解构就会消除响应性

把一个响应式对象转换成普通对象,该普通对象的每个 property 都是一个 ref ,和响应式对象 property 一一对应

export default {
    name: "解构响应式对象数据",
    setup() {
        const user = reactive({
            username: "张三",
            age: 10000,
        });
        return {
            ...toRefs(user)
        };
    },
};



readonly

传入一个对象(响应式或普通)或ref,返回一个原始对象的只读代理。一个只读的代理是“深层的”

对象内部任何嵌套的属性也都是只读的

export default {
  name: "Readonly",
  setup() {
    const original = reactive({ count: 0 });
    const copy = readonly(original);
    setInterval(() => {
      original.count++;
      copy.count++; 
      // 报警告,Set operation on key "count" failed: target is readonly. Proxy {count: 1}
    }, 1000);
    return { original, copy };
  },
};



defineProps

defineProps 是一个仅

你可能感兴趣的:(Vue,vue.js)