关于setup一些细节问题及组件之间的传值
这里创建一个父组件
<template>
<h2>App父级组件</h2>
<h3>msg:{{ msg }}</h3>
<button @click="msg += '==='">更新数据</button>
<hr />
<Child :msg="msg" msg2="真香" @xxx="xxx" />
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
// 引入子级组件Child
import Child from './components/Child.vue'
export default defineComponent({
name: 'App',
// 注册组件
components: {
Child,
},
setup() {
// 定义一个Ref类型的数据
const msg = ref('what are you no sha lei')
function xxx(txt: string) {
msg.value += txt
}
return {
msg,
xxx,
}
},
})
</script>
然后创建一个新的组件
<template>
<h2>Child子级组件</h2>
<h3>msg:{{ msg }}</h3>
<!-- <h3>count:{{ count }}</h3> -->
<button @click="emitXxx">分发事件</button>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
name: 'Child',
props: ['msg'],
// setup细节问题:
// setup是在beforeCreate生命周期回调之前就执行了,而且就执行一次
// 由此可以推断出:setup在执行的时候,当前的组件还没有创建出来,也就意味着:组件实例对象this根本就不能用
// this是undefined,说明,就不能通过this再去调用data/computed/methods/props中的相关内容了
// 其实所有的composition API相关回调函数中也都不可以
// setup中的返回值是一个对象,内部的属性和方法是给html模版使用的
// setup中的对象内部的属性和data函数中的return对象的属性都可以在html模版中使用
// setup中的对象中的属性和data函数中的对象中的属性会合并为组件对象的属性
// setup中的对象中的方法和methods对象中的方法会合并为组件对象的方法
// 在Vue3中尽量不要混合的使用data和setup及methods和setup
// 一般不要混合使用: methods中可以访问setup提供的属性和方法, 但在setup方法中不能访问data和methods
// setup不能是一个async函数: 因为返回值不再是return的对象, 而是promise, 模板看不到return对象中的属性数据
// beforeCreate() {
// console.log('beforeCreate执行了')
// },
// 界面渲染完毕
// mounted() {},
// setup(props,context) {
setup(props, { attrs, slots, emit }) {
// props参数,是一个对象,里面有父级组件向子级组件传递的数据,并且是在子级组件中使用props接收到的所有的属性
// 包含props配置声明且传入了的所有属性的对象
// console.log(props.msg)
// console.log(context.attrs)
// console.log(context.emit)
// context参数,是一个对象,里面有attrs对象(获取当前组件标签上的所有的属性的对象,但是该属性是在props中没有声明接收的所有的尚需经的对象),emit方法(分发事件的),slots对象(插槽)
// 包含没有在props配置中声明的属性的对象, 相当于 this.$attrs
// console.log(context.attrs.msg2)
// console.log('=============')
console.log('setup执行了', this)
const showMsg1 = () => {
console.log('setup中的showMsg1方法')
}
// 按钮的点击事件的回调函数
function emitXxx() {
// context.emit('xxx','++')
emit('xxx', '++')
}
return {
showMsg1,
emitXxx,
// setup中一般都是返回一个对象,对象中的属性和方法都可以在html模版中直接使用
}
},
// data() {
// return {
// count: 10,
// }
// },
// // 界面渲染后的生命周期回调
// mounted() {
// console.log(this)
// },
// // 方法的
// methods: {
// showMsg2() {
// console.log('methods中的showMsg方法')
// },
// },
})
</script>
reactive和ref的一些细节问题
<!--
* @Author: yzz
* @Date: 2021-02-08 14:06:07
* @LastEditors: Do not edit
* @LastEditTime: 2021-02-22 14:33:02
* @Description: Do not edit
* @FilePath: \vue3_study\01_代码\07_ref和reactive的细节问题\App.vue
-->
<template>
<h2>reactive和ref的细节问题</h2>
<h3>m1:{{ m1 }}</h3>
<h3>m2:{{ m2 }}</h3>
<h3>m3:{{ m3 }}</h3>
<hr />
<button @click="update">更新数据</button>
</template>
<script lang="ts">
import { defineComponent, ref, reactive } from 'vue'
export default defineComponent({
name: 'App',
// 是Vue3的 composition API中2个最重要的响应式API(ref和reactive)
// ref用来处理基本类型数据, reactive用来处理对象(递归深度响应式)
// 如果用ref对象/数组, 内部会自动将对象/数组转换为reactive的代理对象
// ref内部: 通过给value属性添加getter/setter来实现对数据的劫持
// reactive内部: 通过使用Proxy来实现对对象内部所有数据的劫持, 并通过Reflect操作对象内部数据
// ref的数据操作: 在js中要.value, 在模板中不需要(内部解析模板时会自动添加.value)
setup() {
// 通过ref的方式设置的数据
const m1 = ref('abc')
const m2 = reactive({
name: '小明',
wife: {
name: '小红',
},
})
// ref也可以传入对象吗
const m3 = ref({
name: '小明',
wife: {
name: '小红',
},
})
// 更新数据
const update = () => {
// ref中如果放入的是一个对象,那么是经过了reactive的处理,形成了一个Proxy类型的对象
console.log(m3)
m1.value += '==='
m2.wife.name += '==='
// m3.value.name += '==='
m3.value.wife.name += '==='
console.log(m3.value.wife)
}
return {
m1,
m2,
m3,
update,
}
},
})
</script>
vue3.0中的computed和watch
<template>
<h2>计算属性和监视</h2>
<fieldset>
<legend>姓名操作</legend>
姓氏:<input
type="text"
placeholder="请输入姓氏"
v-model="user.firstName"
/><br />
名字:<input
type="text"
placeholder="请输入名字"
v-model="user.lastName"
/><br />
</fieldset>
<fieldset>
<legend>计算属性和监视的演示</legend>
姓名:<input type="text" placeholder="显示姓名" v-model="fullName1" /><br />
姓名:<input type="text" placeholder="显示姓名" v-model="fullName2" /><br />
姓名:<input type="text" placeholder="显示姓名" v-model="fullName3" /><br />
</fieldset>
</template>
<script lang="ts">
import {
defineComponent,
reactive,
computed,
watch,
ref,
watchEffect,
} from 'vue'
export default defineComponent({
name: 'App',
setup() {
// 定义一个响应式对象
const user = reactive({
// 姓氏
firstName: '东方',
// 名字
lastName: '不败',
})
// 通过计算属性的方式,实现第一个姓名的显示
// vue3中的计算属性
// 计算属性的函数中如果只传入一个回调函数,表示的是get
// 第一个姓名:
// 返回的是一个Ref类型的对象
const fullName1 = computed(() => {
return user.firstName + '_' + user.lastName
})
// 第二个姓名:
const fullName2 = computed({
get() {
return user.firstName + '_' + user.lastName
},
set(val: string) {
// console.log('=====',val)
const names = val.split('_')
user.firstName = names[0]
user.lastName = names[1]
},
})
// 第三个姓名:
const fullName3 = ref('')
// 监视----监视指定的数据
watch(
user,
({ firstName, lastName }) => {
fullName3.value = firstName + '_' + lastName
},
{ immediate: true, deep: true }
)
// immediate 默认会执行一次watch,deep 深度监视
// 监视,不需要配置immediate,本身默认就会进行监视,(默认执行一次)
// watchEffect(() => {
// fullName3.value = user.firstName + '_' + user.lastName
// })
// 监视fullName3的数据,改变firstName和lastName
watchEffect(() => {
const names = fullName3.value.split('_')
user.firstName = names[0]
user.lastName = names[1]
})
// watch---可以监视多个数据的
// watch([user.firstName,user.lastName,fullName3],()=>{
// // 这里的代码就没有执行,fullName3是响应式的数据,但是,user.firstName,user.lastName不是响应式的数据
// console.log('====')
// })
// 当我们使用watch监视非响应式的数据的时候,代码需要改一下
watch([()=>user.firstName, ()=>user.lastName,fullName3], () => {
// 这里的代码就没有执行,fullName3是响应式的数据,但是,user.firstName,user.lastName不是响应式的数据
console.log('====')
})
return {
user,
fullName1,
fullName2,
fullName3,
}
},
})
</script>
关于toRefs
<template>
<h2>toRefs的使用</h2>
<!-- <h3>name:{{ state.name }}</h3>
<h3>age:{{ state.age }}</h3> -->
<h3>name:{{ name }}</h3>
<h3>age:{{ age }}</h3>
<h3>name2:{{ name2 }}</h3>
<h3>age2:{{ age2 }}</h3>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs } from 'vue'
function useFeatureX() {
const state = reactive({
name2: '自来也',
age2: 47,
})
return {
...toRefs(state),
}
}
export default defineComponent({
name: 'App',
setup() {
const state = reactive({
name: '自来也',
age: 47,
})
// toRefs可以把一个响应式对象转换成普通对象,该普通对象的每个 property 都是一个 ref
// const state2 = toRefs(state)
const { name, age } = toRefs(state)
// console.log(state2)
// 定时器,更新数据,(如果数据变化了,界面也会随之变化,肯定是响应式的数据)
setInterval(() => {
// state.name += '=='
// state2.name.value+='==='
name.value += '==='
console.log('======')
}, 1000)
const { name2, age2 } = useFeatureX()
return {
// state,
// 下面的方式不行啊
// ...state // 不是响应式的数据了---->{name:'自来也',age:47}
// ...state2 toRefs返回来的对象
name,
age,
name2,
age2,
}
},
})
</script>