1. computed计算属性
任何包含响应式数据的复杂逻辑,都应该使用计算属性
计算属性将被混入到组件实例中
所有getter和setter的this 上下文自动的绑定为组件实例
computed计算缓存
computed是有缓存的
也就是说当数据不发生变化时,计算属性时不需要重新计算的
但是如果依赖的数据发生改变了,计算属性依旧会重新进行计算
<divid="app"><!--调用多次--><h2>{{full}}</h2><h2>{{full}}</h2><h2>{{full}}</h2><h2>{{full}}</h2><div>computed: { // 默认是一个函数 fullName() { returnthis.firstName+' - '+this.lastName }, // 也可以是一个对象full:{ get() { //只会打印一次 因为数据没有变化console.log("11111") returnthis.firstName+this.lastName } }, textt:{ get() { returnthis.texts.split(' ').reverse().join(" ") } } },
cumptued计算属性的get和set
computed: { // 对象写法fullName: { get() { returnthis.firsetName+this.lastName }, set(value) { constvalues=value.split(' ') this.firsetName=values[0] this.lastName=values[1] } } }, methods: { btns() { this.fullName="你好 世界" } }
2. watch侦听器
用于声明在数据更改时调用的侦听回调
<divid="app"><h2>{{message}}</h2><button@click="btns">修改</button></div>constapp=Vue.createApp({ data() { return { message: "hello world" } }, methods: { btns() { this.message="你好世界" } }, watch: { message(val, oldval) { console.log("我改变了", val, oldval) } }
侦听器的配置
watch: { info: { handler(newvalue, oldvalue) { console.log(Vue.toRaw(newvalue,oldvalue)) }, // 深度监听deep: true, // 第一次监听immediate:true } }
3. 组件注册
全局组件:在任何其他的组件中都可以使用的组件
局部组件:只有在注册的组件中才能使用的组件
全局组件
import { createApp } from'vue'constapp=createApp({}) app.component( // 注册的名字'MyComponent', // 组件的实现 { /* ... */ } ) <divid="app"><my-home></my-home></div><templateid="test"><h2>你好</h2></template><script>constApp= {} constapp=Vue.createApp(App) app.component("my-home",{ template:'#test', data() { return { } }, m注册局部组件使用components<divid="app"><product-item></product-item></div><templateid="icon"><div><h1>我是一个MyComponent组件</h1><h4>{{title}}</h4></div></template><script>constapp=Vue.createApp({ components: { ProductItem: { template: '#icon', data() { return { title: "我是标题" } } } }, data() { return { } }, methods: { }, computed: { }, wathch: { }, }) // 挂载app.mount("#app")ethods: { }, }) // 挂载app.mount("#app") </script>
局部组件注册
注册局部组件使用components<divid="app"><product-item></product-item></div><templateid="icon"><div><h1>我是一个MyComponent组件</h1><h4>{{title}}</h4></div></template><script>constapp=Vue.createApp({ components: { ProductItem: { template: '#icon', data() { return { title: "我是标题" } } } }, data() { return { } }, methods: { }, computed: { }, wathch: { }, }) // 挂载app.mount("#app")
4. 组件间通信
父组件传递给子组件:通过props属性
子组件传递给父组件:通过$emit触发事件
父组件传递给子组件(props)
场景:子组件传递给父组件需要不同的值时
<template><divclass="app"><!--个人信息一个展示小明一个展示小李--><app-infosname="小明"/><app-infosname="小李"/></div></template>
使用方法:
- 首先在父组件注册一些自定义的attribute
- 父组件给子组件attribute赋值
- 子组件通过props接受对应的attribute
注意:props接受的属性会被暴露到this上
<app-infosname="小明"/><app-infosname="小李"/>exportdefault { props:['name'], data() { return { } }, created() { // props会暴露到 this 上console.log(this.name) } }
Props有两种常见用法
数组和对象
props: { name: { type:String, defalut: '我是默认值' }, age :{ type:Number, defalut: 0 }, // 如果是一个复杂数据类型 必须写一个函数friend: { type:Object, defalut:() => ({ name : 'xiaoluo'} ) } }, exportdefault { props: { // 基础类型检查//(给出 `null` 和 `undefined` 值则会跳过任何类型检查)propA: Number, // 多种可能的类型propB: [String, Number], // 必传,且为 String 类型propC: { type: String, required: true }, // Number 类型的默认值propD: { type: Number, default: 100 }, // 对象类型的默认值propE: { type: Object, // 对象或者数组应当用工厂函数返回。// 工厂函数会收到组件所接收的原始 props// 作为参数default(rawProps) { return { message: 'hello' } } }, // 自定义类型校验函数propF: { validator(value) { // The value must match one of these stringsreturn ['success', 'warning', 'danger'].includes(value) } }, // 函数类型的默认值propG: { type: Function, // 不像对象或数组的默认,这不是一个工厂函数。这会是一个用来作为默认值的函数default() { return'Default function' } } } }
非props的attribute
当父组件传递属性给子组件时,子组件没有用props接受,那么这个属性被称为非props的attribute
非props的attribute会自动添加到子组件的根元素上面
<divclass="app"><!--后面两个属性没有用props接受会自动添加到子组件的根元素上面--><app-infosnames="xiaoluo" :age="20"address="广州市"class="box"/></div>props: { names: { type:String, default: '我是默认值' }, age :{ type:Number, default: 100 } }
如果不想让子组件接收(穿透)可以设置inheritAttrs属性
exportdefault { //设置为false后,非props的attribute不会穿透给子组件的根元素inheritAttrs:false, props: { names: { type:String, default: '我是默认值' }, age :{ type:Number, default: 100 } } }
子组件传递给父组件($emit)
场景:
- 当子组件有一些事件发生时,父组件需要接收
- 子组件有一些内容想要传递给父组件的时候
案列:点击子组件修改父组件的数字
<template><divclass="app"><h2>当前技术:{{counter}}</h2><!--子组件传递的事件--><count-add@addClick="addBtns"></count-add><count-sub@subClick="subBtns"></count-sub></div></template><script>importCountAddfrom"./components/CountAdd.vue"importCountSubfrom"./components/CountSub.vue"exportdefault { components: { CountAdd, CountSub }, data() { return { counter: 0 } }, methods: { addBtns(index) { this.counter+=index }, subBtns(index) { this.counter-=index } } } </script><stylescoped></style><template><divclass="countadd"><divclass="add"><button@click="addCount(1)">+1</button><button@click="addCount(5)">+5</button><button@click="addCount(10)">+10</button></div></div></template><script>exportdefault { // 用于声明由组件触发的自定义事件。emits:['addClick'], methods: { addCount(index) { // 自定义事件 this.$emit("addClick",index) } } } </script><stylelang="less"scoped></style>