1.Vue3整体知识概览图
2.ref与reactive具体使用区别
2-1 基本类型处理
const count1 = ref(0) 使用ref自动转化为数字类型
const count2 = reactive(0) 参数必须是对象类型
2-2 具体使用过程
// ref 处理对象(自动解包)
const user = ref({
name: 'John',
address: {
city: 'New York'
}
})
// 等效于 reactive 写法
const user = reactive({
name: 'John',
address: reactive({
city: 'New York'
})
})
// 访问方式对比
// ref 需要 .value
console.log(user.value.name)
// reactive 直接访问
console.log(user.name)
2-3 数组处理区别
1.ref需要.value.push去修改原数组
const list = ref([1,2,3])
list.value.push(4)
2.reactive 可以直接修改
const list_copy = reactive([1,2,3])
list_copy.push(4)
3.传值
3-1 父子组件传值 普通方式(父传子)
3-1-1 父组件
<template>
<Child :msg='msg' :list="list"/>
</template>
<script>
import Child from './child.vue'
import { ref, reactive } from 'vue'
export default {
components: { Child },
setup() {
const msg = ref('父组件传递给子组件的信息info')
const list = reactive(['苹果', '香蕉', '橘子', '葡萄', '榴莲'])
return {
msg,
list
}
}
}
</script>
3-1-2 子组件
<template>
<ul>
<li v-for='(i,index) in list' :key="index">{{ index+1 }}. {{ i }}</li>
</ul>
</template>
<script>
export default {
props: ['msg', 'list'],
setup() {}
}
</script>
3-2 父子组件传值 setup方式(父传子)
3-2-1 父组件
<template>
<Child :msg='msg' :list="list"/>
</template>
<script>
import Child from './child.vue'
import { ref, reactive } from 'vue'
export default {
components: { Child },
setup() {
const msg = ref('父组件传递给子组件的信息info')
const list = reactive(['苹果', '菠萝蜜', 香蕉', '橘子', '葡萄', '榴莲'])
return {
msg,
list
}
}
}
</script>
3-2-2 子组件
<template>
<ul>
<li v-for='(i,index) in list' :key="index">{{ index+1 }}. {{ i }}</li>
</ul>
</template>
<script setup>
import { defineProps } from 'vue'
const props = defineProps({
// 第一种写法
msg: String,
// 第二种写法
list: {
type: Array,
default: () => []
}
})
console.log(props)
</script>
3-3 emit传值(子传父)
父组件
<template>
<Child @myClick='onMyClick' @increase='onIncrease'/>
</template>
<script setup>
import Child from './child.vue'
const onMyClick = (info) => {
console.log(info)
}
const onIncrease = (info) => {
console.log(info)
}
</script>
子组件
<template>
<button @click="handleClick">按钮</button>
</template>
<script setup>
import { defineEmits, ref } from 'vue'
const info = ref('你好呀')
const emit = defineEmits(['myClick'])
const handleClick = () => {
emit('myClick', info)
emit('increase', ref('你好呀_copy'))
}
</script>
3-4 defineExpose、ref(父传子)
父组件
<template>
<div>父组件:拿到子组件的message数量 {{ msg }}</div>
<button @click='callChildFn'>调用子组件的方法</button>
<Child ref="com"/>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import Child from './child.vue'
const com = ref(null)
const msg = ref('')
onMounted(() => {
console.log(com, 'com==onmounted')
msg.value = com.value.message
})
function callChildFn() {
console.log(com, 'callChildFn==onmounted')
com.value.show()
msg.value = com.value.message
}
</script>
子组件
<template>
<div>子组件</div>
</template>
<script setup>
import { defineExpose, ref } from 'vue'
const message = ref('子组件传递消息')
const show = () => {
console.log('子组件方法')
}
defineExpose({
message,
show
})
</script>
3-5 attrs(子传父)
父组件
<template>
<Child :msg='msg' :msgcopy='msgcopy' title='子组件'/>
</template>
<script setup>
import { ref } from 'vue'
import Child from './child.vue'
const msgcopy = ref('我是你呀')
const msg = ref('你猜我是谁')
</script>
子组件有俩种写法
第一种写法 使用attrs
<template>
<div>子组件: {{ attrs.msg }}--{{ attrs.msgcopy }}--{{ attrs.title }}</div>
</template>
<script setup>
import { useAttrs } from 'vue'
const attrs = useAttrs()
console.log(attrs)
</script>
第二种写法 使用defineProps
<template>
<div>子组件: {{ msg }}--{{ msgcopy }}--{{ title }}</div>
</template>
<script setup>
import { defineProps } from 'vue'
defineProps({
msg: String,
msgcopy: String,
title: String
})
</script>
3-6 provide、inject(多层级传值)
父组件
<template>
<div>祖父组件</div>
<button @click='fn'>改变location的值</button>
<br/>
<div>双向数据绑定:</div>
<ul>
<li>{{ userInfo.name }}</li>
</ul>
<input v-model='userInfo.name' />
<Child />
</template>
<script setup>
import { ref, provide } from 'vue'
import Child from './child.vue'
const location = ref('传递祖父的参数')
const userInfo = ref({
name: '张三',
age: 18
})
function fn() {
location.value = '改变值'
}
provide('location', location)
provide('userInfo', userInfo)
</script>
子组件
<template>
<Sun />
</template>
<script>
import Sun from './sun.vue'
export default {
components: { Sun }
}
</script>
<style lang="scss" scoped>
</style>
孙组件
<template>
<div>
<h5>...........孙组件接受参数........</h5>
<div>1.祖父组件定义provide,孙组件inject接受:{{ location }}</div>
<p>用户信息:{{ userInfo.name }}</p>
<br/>
<br/>
<div>2.provide inject实现父子组件传值的时候,子组件改变数据也会影响父组件</div>
<br/>姓名:
<input v-model="userInfo.name">
</div>
</template>
<script setup>
import { inject } from 'vue'
const location = inject('location')
const userInfo = inject('userInfo')
</script>
再这个里面需要注意的是 readonly
增加readonly后 子组件修改后 不会影响父组件 父组件 子组件和上述一样 唯一区别是孙组件 具体写法如下:
<template>
<div>祖父组件</div>
<button @click='fn'>改变location的值</button>
<br/>
<div>双向数据绑定:</div>
<ul>
<li>{{ userInfo.name }}</li>
</ul>
<input v-model='userInfo.name' />
<Child />
</template>
<script setup>
import { ref, provide,readonly } from 'vue'
import Child from './child.vue'
const location = ref('传递祖父的参数')
const userInfo = ref({
name: '张三',
age: 18
})
function fn() {
location.value = '改变值'
}
provide('location', location)
provide('userInfo', readonly(userInfo))
</script>
3-7 v-model 是vue一个语法糖 在vue3玩法更多了
3-7-1 单个v-model
父组件
<template>
<Child v-model='message'/>
</template>
<script setup>
import { ref } from 'vue'
import Child from './child.vue'
const message = ref('父传给子')
</script>
子组件
<template>
<button @click='handleClick'>修改model</button>
{{ modelValue }}
</template>
<script setup>
import { defineProps, defineEmits } from 'vue'
defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
function handleClick() {
emit('update:modelValue', '子改变值')
}
</script>
<style lang="scss" scoped>
</style>
3-7-2 多个v-model
父组件
<template>
<Child v-model:msg1='message1' v-model:msg2='message2'/>
</template>
<script setup>
import { ref } from 'vue'
import Child from './child.vue'
const message1 = ref('水果1')
const message2 = ref('水果2')
</script>
子组件
<template>
<div>
<button @click='handleClick1'>修改msg1</button> {{ msg1 }}
</div>
<div>
<button @click='handleClick2'>修改msg2</button> {{ msg2 }}
</div>
</template>
<script setup>
import { defineProps, defineEmits } from 'vue'
defineProps({
msg1: String,
msg2: String
})
const emit = defineEmits(['update:msg1', 'update:msg2'])
function handleClick1() {
emit('update:msg1', '蔬菜1')
}
function handleClick2() {
emit('update:msg2', '蔬菜2')
}
</script>
<style lang="scss" scoped>
</style>
3-8 v-model修饰符
1.用法的话是v-model.自定义修饰符 有些自定义修饰符比如trim number lazy
2.具体用法
父组件
<template>
<Child v-model.uppercasefn='message'/>
</template>
<script setup>
import { ref } from 'vue'
import Child from './child.vue'
const message = ref('水果1')
</script>
子组件
<template>
{{ modelValue }}
</template>
<script setup>
import { defineProps, defineEmits, onMounted } from 'vue'
const props = defineProps(['modelValue', 'modelModifiers'])
const emit = defineEmits(['update:modelValue'])
onMounted(() => {
console.log('modelModifiers', props.modelModifiers)
if (props.modelModifiers.uppercasefn) {
emit('update:modelValue', '蔬菜')
}
})
</script>
<style lang="scss" scoped>
</style>
注意:如果在子组件中修改v-model.uppercasefn中的uppercasefn改成其他的 那么页面展示的就是水果1
if (props.modelModifiers.uppercasefn) 这个就是判断自定义修饰符有没有在当前props里
3-9 插槽 slot插槽可以理解为传一段html片段 给子组件
3-9-1 最基础的插槽模版
只需要在子组件中使用标签 就会将父组件传进来的HTML内容渲染出来
父组件
<template>
<Child>
<div>渲染</div>
</Child>
</template>
<script setup>
import Child from './child.vue'
</script>
子组件
<template>
<slot></slot>
</template>
<script setup>
</script>
<style lang="scss" scoped>
</style>
3-9-2 具名插槽
具名插槽就是在默认插槽的基础上进行分类,可以理解为对号入座
父组件需要使用标签 但是需要在标签上使用v-slot:+‘名称’。
子组件需要在标签里用name=‘名称’ 对应接收
父组件
<template>
<Child>
<template v-slot:monkey>
<div>渲染</div>
</template>
<button>我是父组件</button>
</Child>
</template>
<script setup>
import Child from './child.vue'
</script>
子组件
<template>
<div>
<!-- 默认插槽 -->
<slot></slot>
<!-- 具名插槽 也就是自定义插槽 -->
<slot name='monkey'></slot>
</div>
</template>
<script setup>
</script>
<style lang="scss" scoped>
</style>
3-9-3 作用域插槽
父组件
<template>
// v-slot='{scope}' 获取子组件传过来的数据
// :list='list' 把list数据传给子组件
<Child v-slot='{scope}' :list='list'>
<div v-if="scope">
<div>{{ scope.name }}--职业:{{ scope.occupation }}</div>
<hr/>
</div>
</Child>
</template>
<script setup>
import { reactive } from 'vue'
import Child from './child.vue'
const list = reactive([
{ name: '张三', occupation: '学生' },
{ name: '李四', occupation: '老师' },
{ name: '王五', occupation: '医生' },
{ name: '赵六', occupation: '警察' },
{ name: '田七', occupation: '军人' }
])
</script>
子组件
<template>
<div>
<slot v-for='item in list' :scope="item"></slot>
</div>
</template>
<script setup>
import { defineProps } from 'vue'
defineProps({
list: {
type: Array,
default: () => []
}
})
</script>
<style lang="scss" scoped>
</style>
后续还会陆续更新vue3相关文章,敬请期待哈!