关于Vue.js组件巨详细的一篇文章

Posted X可乐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于Vue.js组件巨详细的一篇文章相关的知识,希望对你有一定的参考价值。

文章目录

Vue.js 组件

组件用于封装页面的部分功能,将功能的结构、样式、逻辑代码封装为整体

提高功能的复用性与可维护性,更好地专注于业务逻辑

组件使用时为自定义 html 标签形式,通过组件名作为自定义标签名

<div id="app">
    <!-- 普通 HTML 标签 -->
    <p>P标签内容</p>
    <!-- Vue.js 组件 -->
    <my-com></my-com>
</div>

全局注册

全局注册的组件在注册后可以用于任意实例或组件中

Vue.component('组件名',  /* 选项对象 */ )

注意:全局注册必须设置在根 Vue 实例创建之前

组件基础

本质上,组件是可复用的 Vue 实例,所以它们可以与 new Vue 接收相同的选项,例如 data、methods 以及生命周期钩子等

仅有的例外是像 el 这样的根实例特有的选项

组件命名规则

  • kebab-case: “my-component”
  • PascalCase: “MyComponent”
Vue.component('my-component', /* 选项对象 */)
Vue.component('MyComponent', /* 选项对象 */)

注意:无论采用那种命名方式,在 DOM 中都只有 Kebab-case 可以使用

<div id="app">
  <my-com-a></my-com-a>
  <!-- <MyComA></MyComA> -->
  <my-com-b></my-com-b>
  <!-- <MyComB></MyComB> -->
</div>
<!-- ============================== -->
<script>
  // kebab-case 进行注册
  Vue.component('my-com-a', 
    template: '<div>这是a组件的内容</div>'
  );
  // PascalCase 进行注册
  Vue.component('MyComB', 
    template: '<div>这是b组件的内容</div>'
  );
  new Vue(
    el: '#app',
    data: 
    
  )
</script>

template 选项

template 选项用于设置组件的结构,最终被引入根实例或其他组件中

Vue.component('my-com-a', 
  template: `
    <div>
        <h3>组件A的标题内容</h3>
    </div>
  `
);

注意:组件必须只有一个根元素

data 选项

data 选项用于存储组件的数据,与根实例不同,组件的 data 选项必须为函数,数据设置在返回值对象中

Vue.component('my-com-a', 
  template: `
    <div>
        <h3>组件A的标题内容: title </h3>
    </div>
  `,
  data: function () 
      return 
          title: "示例内容"
      
  
);

这种实现方式是为了确保每个组件实例可以维护一份被返回对象的独立的拷贝,不会互相影响

局部注册

局部注册的组件只能用在当前实例或组件中

new Vue(
    components: 
        'my-component-a': 
            template: `<h3>  title  </h3>`,
            data () 
                return title: "a 组件示例内容"
            
        ,
        'my-component-b': 
            template: `<h3>  title  </h3>`,
            data () 
                return title: "b 组件示例内容"
            
        
    
) 

单独配置组件的选项对象

var MyComponentA =  /* ... */ ;
var MyComponentB =  /* ... */ ;

new Vue(
    el: "#app",
    components: 
        "my-component-a" : MyComponentA,
        "my-component-b" : MyComponentB
    
)

ES6 的对象属性简写

new Vue(
    el: "#app",
    components: 
        MyComponentA,
        MyComponentB
    
)

组件通信

问题:
子组件如何获取父组件中的数据?
父组件如何得知子组件的数据变更?
如果是更加复杂的组件关系呢?

在组件间传递数据的操作,称为组件通信

  • 父传子
  • 子传父
  • 非父子传
  • 其他通信方式

父组件向子组件传值

通过子组件的 props 选项接收父组件的传值

Vue.component('my-component', 
  props: ['title'],
  template: '<h3>  title  </h3>'
)

注意:props 不要与 data 存在同名属性

父组件设置方式如下:

<div id="app">
  <my-component-a title="示例内容1"></my-component-a>
  <my-component-a :title="'示例内容2'"></my-component-a>
  <my-component-a :title="item.title"></my-component-a>
</div>
<!-- ======================= -->
<script>
  new Vue(
    el: "#app",
    data: 
      item: 
        title: "父组件的数据"
      
    
  )
</script>

props 命名规则

建议 prop 命名使用 camelCase,父组件绑定时使用 kebab-case

Vue.component('my-component', 
  props: ['myTitle'],
  template: "<h3>  myTitle  </h3>"
)
<div id="app">
  <my-component-a title="示例内容1"></my-component-a>
  <my-component-a :title="'示例内容2'"></my-component-a>
  <my-component-a :title="item.title"></my-component-a>
</div>

单项数据流

父子组件间的所有 prop 都是单向下行绑定的

如果子组件要处理 prop 数据,应当存储在 data 中后操作

Vue.component(
  props: ['initialTitle'],
  template: '<h3> myTitle </h3>',
  data () 
    return 
      myTitle: this.initialTitle
    
  
)

注意:如果 prop 为数组或对象时,子组件操作将会影响到父组件的状态

props 类型

prop 可以设置类型检查,这时需要将 props 更改为一个带有验证需求的对象,并指定对应类型

Vue.component(
  props: 
    parStr: String,
    parArr: Array,
    parAny: null // parAny: undefined
  ,
  template: `
    <div>
       parStr 
       parArr 
       parAny 
    </div>
  `
)
<script>
  new Vue(
    el: "#app",
    data: 
      str: '示例内容',
      arr: [1, 2, 3],
      any: "任意类型均可"
    
  )
</script>
<!-- ======================= -->
<div id="app">
  <my-component-a
    :par-str = "str"
    :par-arr = "arr"
    :par-any = "any"
  ></my-component-a>
</div>

prop 还可以同时指定多个类型,通过数组方式保存即可

Vue.component('MyComponentA', 
  props: 
    parData: [String, Number]
  ,
  template: `
    <div>
       parData 
    </div>
  `
)

props 验证

当 prop 需要设置多重规则时,可以将 prop 的值设置为选项对象

之前的类型检测功能通过 type 选项设置

Vue.component('MyComponentA', 
  props: 
    parNum: 
      type: Number
    ,
    parData: 
      type: [String, Boolean]
    
  ,
  template: `
    <div>
       parNum 
       parData 
    </div>
  `
)

required 用于设置数据为必填项

Vue.component('MyComponentA', 
  props: 
    parNum: 
      type: Number,
      required: true
    
  ,
  template: `
    <div>
       parNum 
    </div>
  `
)

default 用于给可选项指定默认值,当父组件未传递数据时生效

Vue.component('MyComponentA', 
  props: 
    parNum: 
      type: Number,
      dafault: 100
    
  ,
  template: `
    <div>
       parNum 
    </div>
  `
)

注意:当默认值为数组或对象是,必须为工厂函数返回的形式

Vue.component('MyComponentA', 
  props: 
    parArr: 
      type: Array,
      default: function () 
        return [1, 2, 3]
      
    
  ,
  template: `
    <div>
       parArr 
    </div>
  `
)

validator 用于给传入的 prop 设置校验函数,return 值为 false 时 Vue.js 会发生警告

Vue.component('MyComponentA', 
  props; 
    type: String,
    validator: function (value) 
      return value.startsWitn('lagou');
    
  ,
  template: `
    <div>
       parStr 
    </div>
  `
)

注意:验证函数中无法使用实例的 data、methods 等功能

非 props 属性

当父组件给子组件设置了属性,但此属性在 props 中不存在,这时会自动绑定到子组件的根元素上

<script>
Vue.component('MyComponentA', 
  template: `<p>子组件内容</p>`
)
</script>

<!-- ================== -->

<div id="app">
  <my-component-a
    demo-attr="示例属性"
    title="示例title"
    style="height: 200px"
    class="colorBlue"
  ></my-component-a>
</div>

如果组件根元素已经存在了对应属性,则会替换组件内部的值

class 与 style 是例外,当内外都设置时,属性会自动合并

Vue.component('MyComponentA', 
  template: `
    <p title="原始title" class="fl" style="width: 200px;">子组件内容</p>
  `
)

如果不希望继承父组件设置的属性,可以设置 inheritAttrs: false,但是只适用于普通书写,class 与 style 不受影响

Vue.component('MyComponentA', 
  inheritAttrs: false,
  template: `
    <p title="原始title" class="fl" style="width: 200px;">子组件内容</p>
  `
)

子组件向父组件传值

子向父传值需要通过自定义事件实现

商品为子组件,购物车为父组件,父组件需统计商品个数,就需要在子组件个数变化时传值给父组件

<script>
  new Vue(
    el: "app",
    data: 
      products: [
         id; 1, title: '苹果1斤' ,
         id; 2, title: '橙子2个' ,
         id; 3, title: '香蕉3根' 
      ],
      totalCount: 0
    
  )
</script>
<!-- ========================== -->
<div id="app">
  <h3>购物车</h3>
  <product-item
    v-for="product in products"
    :title="product.title"
    :key="product.id"
  ></product-item>
  <p>总数为: totalCount  </p>
</div>

<!-- 子组件 -->
<script>
Vue.component("product-item", 
  props: ['title'],
  template: `
    <div>
      <span>商品名称: title ;商品个数: count </span>
      <button @click="countIns"> +1 </button>
    </div>
  `,
  data () 
    return  count: 0 
  .
  methods: 
    countIns () 
      this.count++
    
  
)
</script>

子组件数据变化时,通过 $emit() 触发自定义事件

Vue.component('product-item', 
  // ...
  methods: 
    countIns () 
      this.$emit('count-change');
      this.count++
    
  
)

子组件向父组件传值
父组件监听子组件自定义事件,并设置处理程序

<div id="app">
  <!-- ... -->
  <product-item
    @count-change="totalCount++"
  ></product-item>
  <!-- ... -->
</div>

自定义事件传值

子组件触发事件时可以向父组件传值

Vue.component("product-item", 
  props: ['title'],
  template: `
    <div>
      <span>商品名称: title ;商品个数: count </span>
      <button @click="countIns1"> +1 </button>
      <button @click="countIns2"> +5 </button>
    </div>
  `,
  data () 
    return  count: 0 
  .
  methods: 
    countIns1 () 
      this.$emit('count-change', 1);
      this.count++
    
    countIns5 () 
      this.$emit('count-change', 5);
      this.count += 5
    
  
)

父组件在监听事件时需要接受子组件传递的数据

<div id="app">
  <!-- ... -->
  <product-item
    @count-change="totalCount += $event"
  ></product-item>
  <!-- ... -->
</div>

父组件在监听事件时需要接受子组件传递的数据

<div id="app">
  <!-- ... -->
  <product-item
    @count-change="onCountChange"
  ></product-item>
  <!-- ... -->
</div>
<!-- ======================================= -->
<script>
new Vue(
  methods: 
    onCountChange (productCount) 
      this.totalCount += productCount;
    
  
)
</script>

组件与 v-model

v-model 用于组件时,需要通过 props 与自定义事件实现

<div id="app">
  <p>输入内容为: iptValue </p>
  <com-input v-model="iptValue"></com-input>
</div>
<script>
  new Vue(
    el: "#app",
    data: 
      iptValue: ''
    ,
    components: 
      ComInput
    
  )
</script>
<!-- ======================= -->
<script>
  var ComInput = 
    props:['value'],
    template: `
      <input
        type="text"
        :value="value"
        @input="$emit('input', $event.target.value)"
      >
    `
  
</script>

非父子组件传值

兄弟组件或完全无关的两个组件

  • 兄弟组件传值
  • EventBus
  • 其他传值方式

兄弟组件传值

兄弟组件可以通过父组件进行数据中转

<!-- 父 -->
<script>
  new Vue(

以上是关于关于Vue.js组件巨详细的一篇文章的主要内容,如果未能解决你的问题,请参考以下文章

vue实现瀑布流布局的组件/插件总汇

Vue.js 2.x:组件的定义和注册(详细的图文教程)

Vue.js-组件化前端开发新思路

(vue.js)关于Vuejs的$emit和$on传值不成功的问题

Vue.js 创建一个 CNODE 社区

Vue.js 系列教程 2:组件,Props,Slots