【Vue】 - 组件

组件

一、组件注册方式

  1. 组件名为驼峰式(comName)定义时,可以通过 com-name 的形式引用(不区分大小写)
  2. 直接在页面中引用时只能用 kebab-case 的组件名引用(com-name)
一)全局注册

Vue.component('component-name', {})

二)局部注册
new Vue({
  components: {
    'component-a': ComponentA, // component-a 为使用时的组件名,ComponentA为要引入的组件的名字
  }
})
三)模块化
// 定义
<template></template>
export default {}

// 引入
import ComponentA from './ComponentA.vue'
export default {
  components: {
    ComponentA
  },
}

二、组件内容

一)注册参数
Vue.component('component-name', {
    template: '<div></div>', // 组件内容, 一个组件只能有一个根元素
    components: {}, // 组件可以引用其他组件
    props: ['tit'], // 组件通过props接收父级传值, 在组件中可以直接通过this.tit取到tit的值
    data() {
        return {}; // 组件的数据需要通过一个函数来返回一个对象,避免组件复用时数据共享
    },
    methods, // 事件注册,监听器,计算属性,钩子函数与vue实例相同
})
二)监听子组件事件

给组件绑定一个myClick事件,这个事件名是可以自定义的

<div id="wrapper">
    <hello @myClick="addSize"></hello>
</div>

父级中定义对应事件处理函数,子组件中通过$emit(),参数传入事件名(不是处理函数名)来触发

new Vue({
  el: '#wrapper',
  methods: {
    addSize() {console.log(1)}
  }
})

在组件内部绑定事件,通过$emit()来触发父级绑定到子组件上的对应事件,一参为要触发的事件名,其后的参数会作为父级绑定事件的参数

Vue.component('hello', {
  template: `<div @click='$emit("myClick",1,2,3)'>hello</div>` // 通过点击该元素来触发父级的myClick事件
})
三)使用v-model

v-model的作用实际是给元素绑定一个名为 value的属性,然后监听该元素的 input 事件,在触发 input 事件时修改绑定的值

<input v-model='myAge'>
<!-- 等价于 -->
<input :value='myAge' @input='myAge = $enent.target.value'>
<!-- $event是事件对象 -->

要在组件中使用v-model则需要模拟上述过程即可

  1. 通过props接收一个名为 value 的属性
  2. 给组件内的input绑定 value 属性,属性值为 value
  3. 给组件内的input绑定 input 事件处理函数,主动触发父级的 input 事件
<hello v-model='myAge'><hello>
Vue.component('hello', {
  template:
    `<div>
		<input :value='value' @input='$emit('input', $event.target.value)'>
	</div>`,
  props: ['value']
})

三、Prop类型

一)只定义属性名
Vue.component('hello', {
  props: ['value']
})
二)定义类型,如果类型不对会打印警告,但是不影响运行
Vue.component('hello', {
  props: {
    title: String,
    likes: Number,
    isPublished: Boolean,
    commentIds: Array,
    author: Object,
    callback: Function,
    contactsPromise: Promise // or any other constructor
  }
})
三)带验证的props对象,验证失败会打印警告,验证是在组件实例创建前进行的

type的可选值
type:[String,Number,Boolean,Array,Object,Date,Function,Symbol]
type也可以是一个自定义的构造函数,检验时通过 instanceof 来判断

function Person() {}

Vue.component('hello', {
  props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组默认值必须从一个工厂函数获取
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    },
    propG: {
      type: Person // propG instanceof Person
    }
  }
})
四)未定义prop的属性值

如果组件上绑定数据,但是组件内没有对应的prop来接收,这个属性会被绑定到该组件的根元素上
除了 classstyle 之外,父级传递给组件的属性都会替换组件内定义的属性

Vue.component('hello', {
  template:
    `<div>
      <div>hello</div>
    </div>`,
})
<div id="wrapper">
    <hello :noProp="39"></hello>
</div>

<!-- 编译后 -->
<div id="wrapper">
    <div noProp='39'>
      <div>hello</div>
    </div>
</div>
五)禁用prop继承

在组件中设置 inheritAttrsfalse 就能让组件根元素的属性不被传值覆盖
classstyle 不受此属性影响

Vue.component('my-component', {
  inheritAttrs: false,
})

四、自定义事件

一)触发事件

事件名不存在自动化和大小写转换,要触发的事件名需要与定义的事件名完全一致

<my-component @myEvent="doSomething"></my-component>
this.$emit('myEvent')
二)修改v-model默认行为

v-model 默认会利用名为 valueprop 和名为 input 的事件,可以用model选项修改

Vue.component('base-checkbox', {
  model: {
    prop: 'checked', // 将value属性修改为checked属性
    event: 'change' // 将input事件修改为change事件
  },
  props: {
    checked: Boolean // 任需要定义对应的prop
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})
三)监听原生事件

想要直接在组件根元素上监听原生事件需要使用.native修饰符

<base-input v-on:focus.native="onFocus"></base-input>

五、插槽

父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
v-slot:header 可简写为 #header

一)后备内容
  1. 组件中如果没有 slot 标签则父级写在组件标签内的元素都会被抛弃
  2. 在组件的 slot 标签内写入的内容会在父级没有在组件标签内传入内容时展示
Vue.component('hello', {
  template: `
  <div>
    hello <slot>normal Text</slot> 
  </div>
  `
})
<hello></hello>
<!-- 展示为 -->
<div>
  hello normal Text
</div>

<hello>is new Text</hello>
<!-- 展示为 -->
<div>
  hello is new Text
</div>
二)具名插槽

一个不带name的 slot 出口会带有隐含的名字 ‘default’
任何没有被包裹在带有 v-slot 的 中的内容都会被视为默认插槽的内容

// 定义组件时给slot标签一个name属性,引入时传入对应的属性
Vue.component('hello', {
  template: 
    `<div class="container">
        <header>
            <slot name="header"></slot>
        </header>
        <main>
            <slot></slot>
        </main>
        <footer>
            <slot name="footer"></slot>
        </footer>
    </div>`
})
<base-layout>
    <!-- 传入属性即可 -->
    <template v-slot:header>
        <h1>Here might be a page title</h1>
    </template>

    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
    <!-- 等价于
    <template v-slot:default>
      <p>A paragraph for the main content.</p>
      <p>And another one.</p>
    </template> 
    -->

    <template #:footer>
        <p>Here's some contact info</p>
    </template>
</base-layout>
三)作用域插槽

插槽总是在父级组件中使用的,这时的作用域是在父级中,插槽拿不到组件内的数据
这时如果需要调用组件里的数据就要用到作用域插槽,在组件内把属性值赋给插槽

// 定义组件时给slot标签一个name属性,引入时传入对应的属性
Vue.component('hello', {
  template: 
  `<div class="container">
      <slot name="header" :uName='innerName' :uAge='innerAge'></slot>
  </div>`,
  data() {
      return {
          innerName:'zhangkb',
          innerAge: 099
      }
  }
}
<hello>
  <!-- msg就是接收到的组件内传给插槽的数据对象 -->
  <template v-slot:header='{msg}'>
    <h1>get slot data: {{mag.uName + msg.uAge}}</h1>
</template>
</hello>

<!-- 展示为 -->
<h1>get slot data: zhangkb099</h1>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值