Vue学习笔记---初识组件

前言

Vue中,万物皆组件,学习组件乃是Vue的根基所在,假如一个页面相当于一张图,那么组件就是一个小小的拼图,通过组件可以拼出各式各样的图,这也是Vue的魅力所在。

正文

基本示例

Vue.component('button-counter',{
    data() {
      return {
        count: 0
      }
    },
    template: ''
})

上面我们创建了一个全局的名字为button-couter的组件,当我们要在根实例(app.vue)中使用它的时候,直接把这个组件作为自定义的标签来使用。

局部注册

上面演示了如何全局注册一个组件,但是组件不能全部都全局注册,会造成代码的冗余,所以大部分的组件需要局部注册。

如何局部注册呢,首先把一个组件作为一个单个的文件放在components文件夹下,在文件中将组件export,然后在实例中import它就实现了组件的局部注册。

// 组件文件的基本格式
// components/buttonCounter.vue



下面我们在实例中调用它

import buttonCounter from './component/buttonCounter'
// 引入组件,组件的名字也可以随意定义(假如定一个abc),下面使用它的时候就用

基础组件的自动全局化注册

有一些组件特别小,但是复用率特别高,必须输入框按钮之类的,这些组件就必须全局注册,但是组件又特别多,一个个注册显得代码特别臃肿,所以下面就用一段代码来实现自动注册。

假如我们把基础组件放在components文件夹下,组件的文件名都以Base开头,比如BaseInput,BaseButton。首先我们引入符合Base开头匹配规则的所有组件,这里要用到require.context方法,然后用文件的名字来注册全局组件。

import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'

const requireComponent = require.context(
    './components',  //根目录
    false,            // 是否查询子目录
    /Base[A-Z]\w+\.(vue|js)$/   //匹配规则
)
requireComponent.keys().forEach(fileName => {
    const componentConfig = requireComponent(fileName)

    const componentName = upperFirst(
        camelCase(
            fileName.replace(/^\.\/(.*)\.\w+$/, '$1')
        )
    )
    Vue.component(
        componentName,
        componentConfig.default || componentConfig
        // 组件中 export default 和 export
    )
})

上面代码中upperFirstcamelCase都是lodash库里面的方法。

组件里面也是有computed,methods,watch生命周期钩子的,唯独没有el,这是根实例独有的

那么data为何是个函数而不是对象呢,这是因为组件是可以复用的,每次使用就创建一个新的实例,把data里面的属性作为函数的返回值的话,它就实现了每个实例的属性的私有化,跟闭包一样原理。

通过prop向组件传递数据

Vue.component('blog-post',{
    props: ['title','name'],
    template: '

{{ name }}{{ title }}

' })

我们创建了一个blog-post组件,并用prop接收了2个参数titlename,下面在根实例中往组件中注入值


上面是传了几个单个值,假如传的值比较多,或者传的值是个数组的时候就要换一个方式

Vue.component('blog-post',{
    props: ['post'],
    template: '

{{ post.name }}{{ post.title }}

' })

根实例中传值


当父级传给子组件值时候,子组件改变这个值也会同时更改父级的值,这样就会发生混乱,所以当子组件有改变值的情况下,最好将父级传来的值赋给自己的属性

props: ['name'],
data() {
  return {
    myName: this.name
  }
}

组件向父级传值

这里要用到一个Vue的内置方法$emit,这个函数就相当于js中的trigger(),就是在组件中可以触发实例中绑定的事件,而且这个方法可以传递参数。

Vue.component('welcome-button', {
  template: `
    
  `
})

组件中触发welcome事件并传了个参数1,那么在实例中绑定这个事件




new Vue({
    data: {
      couter: 0
    },
    methods: {
      sayHi(argsCouter) {
        // ..
      }
    }
})

在实例中可以使用$event获取$emit传递的参数,如果$emit触发的事件引用的是另外一个事件,那么$emit的参数将传给它引用的事件(argsCouter即$emit传递的参数)

在组件中使用v-model

这是一个v-model的使用场景,那么它的本质其实是


那么在组件上使用v-model就相当于


等同于

为了让它工作,在组件中首先得把value绑在prop上,然后它得触发input事件

Vue.component('custom-input',{
    prps: ['value'],
    template: `

插槽

有时候我们在调用组件的时候,组件元素中间还有一些其他的东西,一般情况下,如果不处理这些东西会被舍弃的,但是如果加上元素,这些东西就会被渲染在组件之中


这是一个链接

那么在组件中,如果要使用这是一个链接,就需要加元素


     //这是一个链接

组件元素的闭合标签中间内容就是插槽,在插槽可以加html模板,甚至可以加组件

具名插槽

上面的只是一个插槽,那它默认渲染的就是组件中的,但是当有多个插槽,并且插槽还有指定位置的时候,就必须要给加上name属性

那么在父级提供插槽内容的时候,必须加一个