VUE学习-基础入门04--组件

组件注册

全局注册

  • 全局注册的组件可以在此应用的任意组件的模板中使用
    import { createApp } from 'vue'
    import MyComponent from './App.vue'
    
    const app = createApp({})
    
    app.component('MyComponent', MyComponent)
    

局部注册

  1. 使用 <script setup> 的单文件组件

    <script setup>
    import ComponentA from './ComponentA.vue'
    </script>
    
    <template>
      <ComponentA />
    </template>
    
  2. 没有使用 <script setup>

    import ComponentA from './ComponentA.js'
    
    export default {
      components: {
        ComponentA
      },
      setup() {
        // ...
      }
    }
    

Props–父传子参数

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

Props类型

  1. 字符串数组,[‘foo’, ‘bar’]
  2. 对象,{ title: String, likes: Number }

定义

  • 使用 <script setup> 的单文件组件

    <script setup>
    const props = defineProps(['foo'])
    
    console.log(props.foo)
    </script>
    
  • 不使用 <script setup>

    export default {
      props: ['foo'],
      setup(props) {
        // setup() 接收 props 作为第一个参数
        console.log(props.foo)
      }
    }
    
  • 使用TypeScript时:

    <script setup lang="ts">
    defineProps<{
      title?: string
      likes?: number
    }>()
    </script>
    

传递 prop 的细节

  • Prop 名字格式

    • 子组件
      defineProps({
        greetingMessage: String
      })
      // =================================
      
      <span>{{ greetingMessage }}</span>
      
    • 父组件
      <MyComponent greeting-message="hello" />	
      
  • 静态 vs. 动态 Prop

    • 静态
      <BlogPost title="My journey with Vue" />
      
    • 动态 ,使用 v-bind 或缩写 :
      <!-- 根据一个变量的值动态传入 -->
      <BlogPost :title="post.title" />
      
      <!-- 根据一个更复杂表达式的值动态传入 -->
      <BlogPost :title="post.title + ' by ' + post.author.name" />
      
  • 传递不同的值类型

    • Number
      <!-- 虽然 `42` 是个常量,我们还是需要使用 v-bind -->
      <!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
      <BlogPost :likes="42" />
      
      <!-- 根据一个变量的值动态传入 -->
      <BlogPost :likes="post.likes" />
      
    • Boolean
      <!-- 仅写上 prop 但不传值,会隐式转换为 `true` -->
      <BlogPost is-published />
      
      <!-- 虽然 `false` 是静态的值,我们还是需要使用 v-bind -->
      <!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
      <BlogPost :is-published="false" />
      
      <!-- 根据一个变量的值动态传入 -->
      <BlogPost :is-published="post.isPublished" />
      
    • Array
      <!-- 虽然这个数组是个常量,我们还是需要使用 v-bind -->
      <!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
      <BlogPost :comment-ids="[234, 266, 273]" />
      
      <!-- 根据一个变量的值动态传入 -->
      <BlogPost :comment-ids="post.commentIds" />
      
    • Object
      <!-- 虽然这个对象字面量是个常量,我们还是需要使用 v-bind -->
      <!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
      <BlogPost
        :author="{
          name: 'Veronica',
          company: 'Veridian Dynamics'
        }"
       />
      
      <!-- 根据一个变量的值动态传入 -->
      <BlogPost :author="post.author" />
      
  • 使用一个对象绑定多个 prop

    const post = {
      id: 1,
      title: 'My Journey with Vue'
    }
    
    <!--  -->
    <BlogPost v-bind="post" />
    <!-- 等价与 -->
    <BlogPost :id="post.id" :title="post.title" />
    

Prop 校验

defineProps() 宏中的参数不可以访问 <script setup> 中定义的其他变量,因为在编译时整个表达式都会被移到外部的函数中。

defineProps({
  // 基础类型检查
  // (给出 `null` 和 `undefined` 值则会跳过任何类型检查)
  propA: Number,
  // 多种可能的类型
  propB: [String, Number],
  // 必传,且为 String 类型
  propC: {
    type: String,
    required: true
  },
  // Number 类型的默认值
  propD: {
    type: Number,
    default: 100
  },
  // 对象类型的默认值
  propE: {
    type: Object,
    // 对象或数组的默认值
    // 必须从一个工厂函数返回。
    // 该函数接收组件所接收到的原始 prop 作为参数。
    default(rawProps) {
      return { message: 'hello' }
    }
  },
  // 自定义类型校验函数
  propF: {
    validator(value) {
      // The value must match one of these strings
      return ['success', 'warning', 'danger'].includes(value)
    }
  },
  // 函数类型的默认值
  propG: {
    type: Function,
    // 不像对象或数组的默认,这不是一个工厂函数。这会是一个用来作为默认值的函数
    default() {
      return 'Default function'
    }
  }
})
  • 所有 prop 默认都是可选的,除非声明了 required: true

  • Boolean 外的未传递的可选 prop 将会有一个默认值 undefined

  • Boolean 类型的未传递 prop 将被转换为 false。这可以通过为它设置 default 来更改——例如:设置为 default: undefined 将与非布尔类型的 prop 的行为保持一致。

  • 如果声明了 default 值,那么在 prop 的值被解析为 undefined 时,无论 prop 是未被传递还是显式指明的 undefined,都会改为 default 值。

Boolean 类型转换

  • 子组件的部分内容

    defineProps({
      disabled: Boolean
    })
    
  • 父组件的部分内容

    <!-- 等同于传入 :disabled="true" -->
    <MyComponent disabled />
    
    <!-- 等同于传入 :disabled="false" -->
    <MyComponent />
    

组件事件–子向父传递事件

声明触发的事件

  • <script setup>

    <script setup>
    const emit = defineEmits({
      submit(payload) {
        // 通过返回值为 `true` 还是为 `false` 来判断
        // 验证是否通过
      }
    })
    </script>
    <script setup>
    const emit = defineEmits(['inFocus', 'submit'])
    
    function buttonClick() {
      emit('submit')
    }
    </script>
    
  • <script setup lang="ts">

    <script setup lang="ts">
    const emit = defineEmits<{
      (e: 'change', id: number): void
      (e: 'update', value: string): void
    }>()
    </script>
    
  • <script setup>

    • 非解构

      export default {
        emits: ['inFocus', 'submit'],
        setup(props, ctx) {
          ctx.emit('submit')
        }
      }
      
    • 解构

      export default {
        emits: ['inFocus', 'submit'],
        setup(props, { emit }) {
          emit('submit')
        }
      }
      

基本用法

  • 子组件

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

    <MyComponent @some-event="callback" />
    <!-- 监听器也支持 .once 修饰符 -->
    <MyComponent @some-event.once="callback" />
    

事件参数

  • 子组件

    <button @click="$emit('increaseBy', 1)">
      Increase by 1
    </button>
    
  • 父组件

    <!--内连函数 -->
    <MyButton @increase-by="(n) => count += n" />
    
    
    <!--方法函数 -->
    <MyButton @increase-by="increaseCount" />
    ...
    ...
    function increaseCount(n) {
      count.value += n
    }
    

事件校验

  • 事件校验
    <script setup>
    const emit = defineEmits({
      // 没有校验
      click: null,
    
      // 校验 submit 事件
      submit: ({ email, password }) => {
        if (email && password) {
          return true
        } else {
          console.warn('Invalid submit event payload!')
          return false
        }
      }
    })
    
    function submitForm(email, password) {
      emit('submit', { email, password })
    }
    </script>	
    

配合 v-model 使用

  • 1
    • 子组件

      <script setup>
      defineProps(['modelValue'])
      defineEmits(['update:modelValue'])
      </script>
      
      <template>
        <input
          :value="modelValue"
          @input="$emit('update:modelValue', $event.target.value)"
        />
      </template>
      
    • 父组件

      <script setup>
      import { ref } from 'vue'
      import CustomInput from './CustomInput.vue'
        
      const message = ref('hello')
      </script>
      
      <template>
        子组件input:<CustomInput v-model="message" />
        <br>
        父组件input:<input v-model="message" />
        <br>
        父组件显示:{{ message }}
      </template>
      
    • 显示

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值