vue组件封装指南

目录

vue组件三要素

  1. props参数
  2. slot定制插槽
  3. event自定义事件

基本用法

在使用 vue-cli 建立的项目中,组件的建立很是方便,只须要新建一个 .vue 文件,而后在 template 中写好 HTML 代码,一个简单的组件就完成了 一个完整的组件,除了 template 之外,还有 script和 stylecss

<template>
  <div class="headComponent">
    子组件{{{myData}}
  </div>
</template>

<script>
export default {
    props:['data','type'],
    inheritAttrs: false,
    data(){
        return{
            myData:'',
        }
    },
    mounted(){

    },
    methods:{
       
    }
}
</script>
<style scoped>

</style>
复制代码

而后在其余文件的 js 里面引入并注册,就能直接使用这个组件了html

import list from '../components/headComponent.vue'
复制代码

1、props:数据父组件传入子组件

父对子传参,就须要用到 props,一般的 props 是这样的:vue

props:['data','type']
复制代码

可是通用组件的的应用场景比较复杂,对 props 传递的参数应该添加一些验证规则,经常使用格式以下:ajax

props: {
    // 基础类型检测 (`null` 意思是任何类型均可以)
    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 value > 10
      }
    }
  }
复制代码

对于经过 props 传入的参数,不建议对其进行操做,由于会同时修改父组件里面的数据 // vue2.5已经针对 props 作出优化,这个问题已经不存在了 若是必定须要有这样的操做,能够这么写:vue-router

let copyData = JSON.parse(JSON.stringify(this.data))
复制代码

为何不直接写 let myData = this.data 呢? 由于直接赋值,对于对象和数组而言只是浅拷贝,指向的是同一个内存地址,其中一个改变另外一个也会改变。而经过 JSON颠倒转换以后,实现了深拷贝,则能够互不影响。vue-cli

2、子组件触发父组件事件

在通用组件中,一般会须要有各类事件,好比复选框的 change 事件,或者组件中某个按钮的 click 事件,有时子组件须要触发一个事件,并传递给父组件数组

// 子组件方法:触发父组件方法,并传递参数data到父组件
handleSubmit(data){
    this.$emit('submitToParent', data)
}
复制代码
// 父组件调用子组件
<child-component @submitToParent="parentSubmit"></child-component>
... ...
// 父组件中被触发的方法,接受到子组件传来的参数
parentSubmit(data){
    // 父组件的逻辑处理
}
复制代码

父组件中的逻辑要放在父组件处理,子组件基于父组件的数据作的逻辑放在子组件中处理; 这样既下降了耦合性,也保证了各自的数据不被污染。bash

3、记得留一个 slot

一个通用组件,每每不可以完美的适应全部应用场景 因此在封装组件的时候,只须要完成组件 80% 的功能,剩下的 20% 让父组件经过 solt 解决session

上面是一个通用组件,在某些场景中,右侧的按钮是 “处理” 和 “委托”。在另外的场景中,按钮须要换成 “查看” 或者 “删除” 在封装组件的时候,就不用写按钮,只须要在合适的位置留一个 slot,将按钮的位置留出来,而后在父组件写入按钮函数

子组件
<div class="child-btn">
    <!-- 具名插槽 -->
    <slot name="button"></slot>
    <!-- 匿名插槽(每一个组件只能有一个) -->
    <slot><slot>
</div>

父组件
<child>
    <!-- 对应子组件中button的插槽 -->
    <button slot="button">slot按钮</button>
</child>
复制代码

开发通用组件的时候,只要不是独立性很高的组件,建议都留一个 slot,即便还没想好用来干什么。

再来个例子:

开发过程当中,经常须要在子组件内添加新的内容,这时候能够在子组件内部留一个或者多个插口

而后在调用这个子组件的时候加入内容

添加的内容就会分发到对应的 slot 中

slot 中还能够做为一个做用域,在子组件中定义变量,而后在父组件中自定义渲染的方式 子组件:

父组件:

这个示例中,首先在子组件中添加 slot,并在子组件中定义了数组变量 navs 而后在父组件中以做用域 template 添加内容,其中 scope 是固有属性,它的值对应一个临时变量 props 而 props 将接收从父组件传递给子组件的参数 navs

关于slot的用法还可查看:juejin.im/post/5cc856…

4、Vuex:巧用但不要滥用

子组件向子组件传递数据

Vue 没有直接子对子传参的方法,建议将须要传递数据的子组件,都合并为一个组件。若是必定须要子对子传参,能够先从传到父组件,再传到子组件。 父子组件之间是经过 props 和 自定义事件来传参,非父子组件一般会采用 Vuex 传参 Vuex设计初衷是用来管理组件状态,也能够用于复杂组件的参数传递

可是 Vuex 的虽然能够用来传参,但并不推荐;由于 Vuex 相似于一个全局变量,会一直占用内存 在写入数据庞大的 state 的时候,就会产生内存泄露(人是活的,不能由于事物有弊端就不使用,合理利用便可)。 Tips: 当页面刷新的时候,Vuex 会初始化,同时也会丢失编辑过的数据 若是刷新页面时须要保留数据,能够经过 url 或者 sessionstorage 保存 id,而后 ajax 请求数据

5、组件的css:合理运用 scoped 控制样式做用域

在编写组件的时候,能够在 style 标签中添加 scoped,让标签中的样式只对当前组件生效 可是一味的使用 scoped,确定会产生大量的重复代码 因此在开发的时候,应该避免在组件中写样式 当全局样式写好以后,再针对每一个组件,经过 scoped 属性添加组件样式

6、动态组件

Vue 还能够将多个子组件,都挂载在同一个位置,经过变量来切换组件,实现 tab 菜单这样的效果

这样的功能能够经过路由 vue-router 实现,但路由更适合较大的组件,并且 url 会有相应的改变 Vue 自身保留的 元素,能够将组件动态绑定到 is 特性上,从而很方便的实现动态组件切换
上例中,当 tabView 的值改变,component 就会渲染对应的组件,和路由的效果十分相似,可是地址栏并无发生改变,但这样一来,每次切换组件都会从新渲染,没法保留组件上的数据。这时可使用 ** keep-alive ** 将组件保留在内存中,避免从新渲染

7、递归组件

当组件拥有 name 属性的时候,就能够在它的模板内递归的调用本身,这在开发树形组件的时候十分有效

上面是一个子组件,定义了 name 为 simple03,而后在模板中调用自身,结合 v-for 实现递归 为了防止出现死循环,在调用自身的时候,加入了 v-if 做为断定条件 父组件中调用的时候,须要经过 props 传入一个 tree:

最终渲染结果:

其余状况

子组件改变父组件的数据

在vue2.0以后的版本中,不容许子组件直接改变父组件的数据,在1.0的版本中能够这样操做的,可是每每项目需求须要改变父组件的数据,那咱们如何变通呢? 当咱们把父元素的数据给子组件时,要传一个非基础类型,即传递对象or数组,子组件经过访问对象中的属性操做数据,由于对象和数组是传引用,因此在子组件中修改的时候,父组件也会同步改变,以下:

// 父组件要props传递给子组件的数据
myData:{
    info:'父组件信息'
}

// 子组件
 <template id="tpl">
    <div>
        <button @click="change">change</button>
        <p>{{data.info}}</p>
    </div>
</template>
... 省略部分无关代码 ...
props:['data'],
methods:{
    change(){
        this.data.info = 'change info'
    }
}
复制代码

当子组件点击change按钮改变数据的时候,父组件也会同步改变

若是不想影响父组件的值,咱们也能够用文章开头讲的JSON颠倒转换的方式,在mounted方法中进行深拷贝,在data中初始化数据时用另外一个变量做为承载,这样才承载变量改变,就不会影响父组件该变量的值了。

参考博客: www.cnblogs.com/wisewrong/p… www.cnblogs.com/yesyes/p/66…

相关文章
相关标签/搜索