vue3 深入组件

组件注册

全局注册 使用 .component() 方法

import {createApp} from 'vue';

const app = createApp({})

import ComponentA from './ComponentA';
app.component('ComponentA',ComponentA)

局部注册 在使用  <script></script> 单文件组件中,导入组件即可直接在模板中使用,无需注册

<script setup>
import ComponentA from './ComponentA.vue'
</script>

<template>
  <ComponentA />
</template>

组件名格式

使用 PascalCase 作为组件名的注册格式,Vue 支持将模板中使用 kebab-case 的标签解析为使用 PascalCase 注册的组件。这意味着一个以MyComponent为名注册的组件,在模板中可以通过 <MyComponent> 或 <my-component> 引用

Props

在使用<script setup> 的单文件组件中,props 可以使用 defineProps() 宏来声明:

<script setup>
const props = defineProps(['foo']) //数组类型

// 对象类型
const props2 = defineProps({
  title: String,
  likes: Number,
  example:{
        default(){
            return '默认值'
        },
        type:String,
        require:false
    }
})

console.log(props.foo)
</script>

使用一个对象绑定多个prop

如果你想要将一个对象的所有属性都当作 props 传入,你可以使用没有参数的 v-bind ,即只使用 v-bind而非 :prop-name

const post = {
    id:1,
    title:'这是一个标题'
}

<Component v-bind="post" />

实际上等价于
<Component :id="post.id" :title="post.title" />

单向数据流

所有的props 都遵循单向绑定原则,props 因父组件更新而变化,将新的状态向下流往子组件,不会逆向传递。

1.prop 被用于传入初始值;而子组件想在之后将其作为一个局部数据属性。在这种情况下,最好是新定义一个局部数据属性,从 props 上获取初始值即可:

const props = defineProps(['initialCounter'])

// 计数器只是将 props.initialCounter 作为初始值
// 像下面这样做就使 prop 和后续更新无关了
const counter = ref(props.initialCounter)

2.需要对传入的 prop 值做进一步的转换。在这种情况中,最好是基于该 prop 值定义一个计算属性:

const props = defineProps(['size'])

// 该 prop 变更时计算属性也会自动更新
const normalizedSize = computed(() => props.size.trim().toLowerCase())

组件事件

在组件模板中,可直接使用 $emit 方法触发自定义事件

<!-- MyComponent -->
<button @click="$emit('someEvent')">click me</button>

<MyComponent @some-event="callback" />

在<script setup>中 使用 defineEmits

<script setup>
const emit = defineEmits(['inFocus'])

function buttonClick(){
    emit('inFocus')
}
</script>

事件校验

要为事件添加校验,那么改事件可被复制一个函数,接受的参数就是抛出事件时传入emit的内容,返回一个布尔值来表明事件是否合法

<script setup>
const emit = defineEmits({
    //没有校验
    click:null,
    // 校验submit事件
    submit:({email,password})=>{
        if(email && password) {
            return true
        }else{
            console.warn('传参不对')
            return false
        }
    }
})

function submitForm(email,password){
    emit('submit',{email,password})
}    
</script>

组件v-model

v-model 可以在组件上使用以实现 双向绑定。

从vue3.4 开始, 推荐实现方式是使用 defineModel() 宏:

// Parent.vue
<Child v-model="count"/>

// Child.vue
<script setup>
const model = defineModel()
function update(){
    model.value++
}
// defineModel 还可设置默认值、必填
const model2 = defineModel({require:true,default:0})



</script>

<template>
<p>父组件绑定的值是 {{model}}</p>
<input v-model="model" />
</template>

defineModel() 返回的值是一个 ref 。它可以像其他ref 一样被访问以及修改,不过它能起到父组件和当前变量之间的双向绑定作用.

v-model 的参数

组件上的v-model 也可以接受一个参数,在子组件中,可通过字符串作为第一个参数传递 defineModel() 来支持相应的参数

<MyComponent v-model:title="bookTitle" v-model:last-name="last">


// MyComponent.vue
<script setup>
const title = defineModel('title');
const lastName = defineModel('lastName')
// 额外传递prop选项
const title = defineModel('title',{require:true})
</script>

<template>
<input type="text" v-model="title" />
</template>

插槽Slots

<button type="submit">
  <slot>
    Submit <!-- 默认内容 -->
  </slot>
</button>

<SubmitButton />  // “Submit”将会被作为默认内容渲染:
<SubmitButton>Save</SubmitButton>  // “Save” 会被显示 被显式提供的内容会取代默认内容

具名插槽 

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>


<BaseLayout>
    <template v-slot:header>
    // header 插槽内容放这里
    </template>
    <template #main> // # 简写
    // main插槽内容放这里
    </template>
    <template v-slot:[dynamicSlotName]>
    // 动态插槽名
    </template>
    <template #[dynamicSlotName]>
    // 动态插槽名
    </template>
</BaseLayout>

依赖注入

provide 和 inject,解决父级组件向所有后代组件传递数据,不需要层层传递。

Provide(提供)

<script setup>
    import {ref,provide,readonly} from 'vue';

   // provide(注入名,值)
    const count = ref(0);
    provide('message',count)
    // 传入数据不被注入方更改
    provide('message',readonly(count))
</script>

应用层provide

import { createApp } from 'vue'

const app = createApp({})

app.provide(/* 注入名 */ 'message', /* 值 */ 'hello!')

Inject(注入)

<script setup>
import {inject} from 'vue'
const message = inject('message','默认值')
</script>

在一些场景中,默认值可能需要通过调用一个函数或初始化一个类来取得。为了避免在用不到默认值的情况下进行不必要的计算或产生副作用,我们可以使用工厂函数来创建默认值:第三个参数表示默认值应该被当作一个工厂函数。

const value = inject('key', () => new ExpensiveClass(), true)

和响应式数据配合使用

需要在注入方组件中更改数据时,需传递一个更改数据的方法函数

<!-- 在供给方组件内 -->
<script setup>
import { provide, ref } from 'vue'

const location = ref('North Pole')

function updateLocation() {
  location.value = 'South Pole'
}

provide('location', {
  location,
  updateLocation
})
</script>

// 在注入方组件
<script setup>
import {inject} from 'vue';
const {location,updateLocation} = inject('location)
</script>

<template>
<button @click="updateLocation">{{location}}</button>
</template>

  • 29
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值