VUE组件化开发的精髓

5,956 阅读5分钟
  • 开篇:vue.js的简单介绍和演示
  • vue的开发精髓-组件
  • vue组件的三个API:prop、event、slot
  • 组件之间的通信方式
  • 实例讲解:銖宝益帮助中心前端组件

开篇:vue.js的简单介绍和演示

vue发布于2013年,是一个渐进式的框架, 同时也是一个轻量级的框架,它只关心数据,从而让开发者不用过多的关注DOM的改变和操作DOM,vue的作者为Evan You(尤雨溪),任职于Google Creative Lab

DOM:document object model(文档对象模型)也就是操作html或xml的通用编程接口,这里不过度描述

双向绑定代码演示
// html
<body>
    <div id="app">
        <input type="text" v-model="note">
        <p>{{ note }}</p>
    </div>
</body>

// js
var app = new Vue({
    el: '#app',
    data: {
        note: ''
    }
})

对比其它web前端框架,vue更容易上手,代码和API更为简洁和直观,且速度更快!

vue的开发精髓-组件

vue最精髓的,正是它的组件与组件化,写一个 Vue 工程,其实就是在写一个个的组件。

vue组件的分类(三大类)
  1. 由 ==vue-router产生的每个页面==,它本质上也是一个组件(.vue),主要承载当前页面的 HTML 结构,会包含数据获取、数据整理、数据可视化等常规业务。整个文件相对较大,因为它作为路由的渲染,不会被复用,因此也不会对外提供接口;在项目开发中,我们写的大部分代码都是这类的组件(页面),协同开发时,每人维护自己的页面,很少有交集。这类组件相对是最好写的,因为主要是还原设计稿,完成需求,不需要太多模块和架构设计上的考虑;
  2. 不包含业务,独立、具体功能的==基础组件==,比如日期选择器、模态框等。这类组件作为项目的基础控件,会被大量使用,因此组件的 API 进行过高强度的抽象,可以通过不同配置实现不同的功能;
  3. ==业务组件==。它不像第二类独立组件只包含某个功能,而是在业务中被多个页面复用的,它与独立组件的区别是,业务组件只在当前项目中会用到,不具有通用性,而且会包含一些业务,比如数据请求;而独立组件不含业务,在任何项目中都可以使用,功能单一,比如一个具有自定义数据校验功能的输入框。

vue组件的三个API:prop、event、slot

一个组件的复杂与否,都是由三部分组成的,==prop(属性)==,==event(事件)==,==slot(插槽)==,必须要先设计好这三部分,才能继续开发组件,否则,代码一旦发布,后面再修改API就很困难了,组件的维护都是以新增功能为主,而不是经常变更接口;

prop(属性)

prop 定义了这个组件有哪些可配置的属性,组件的核心功能也都是它来确定的。写通用组件时,props 最好用对象的写法,这样可以针对每个属性设置类型、默认值或自定义校验属性的值,这点在组件开发中很重要,然而很多人却忽视,直接使用 props 的数组用法,这样的组件往往是不严谨的。

例如:收银端的打印弹框组件(部分代码已简略)

<template>
  <!--打印-->
  <el-dialog
    :show-close="false"
    :visible="visiable"
    :closeOnClickModal="false"
    custom-class="zbe-dialog chose-sale"
    width="1000px"
    center
  >
    <p slot="title" class="zbe-dialog-title">打印单据</p>
    <div class="box">
      <el-row style="margin-top:10px">
        <el-col :span="24" v-if="!web_view_error" v-loading="loading">
          <!-- 预览窗口 -->
          <webview
            ref="view"
            id="view"
            :src="visiable?data_web_view_url:' '"
            autosize
            plugins
            disablewebsecurity
            allowpopups
            style="display:inline-flex; width:100%;height:400px;"
          ></webview>
        </el-col>
        <!-- 打印加载失败提示 -->
        <el-col :span="24" v-if="web_view_error&&!loading">打印加载失败</el-col>
      </el-row>
      <!-- 关闭按钮 -->
      <el-row>
        <el-col :span="11" :offset="20" style="margin-top:20px">
          <el-button @click="doCancle">关闭</el-button>
        </el-col>
      </el-row>
    </div>
  </el-dialog>
</template>
<script>
export default {
  name: "print",
  props: {
    // 控制组件的显示隐藏
    show: {
      type: Boolean,
      default: false
    },
    // 打印URL
    web_view_url: "",
    // 关闭打印后的跳转地址
    web_view_reback_path: "",
    // 是否打印加载失败
    web_view_error: false
  },
  data() {
    return {
      visiable: false,
      domReady: true,
      data_web_view_url: "/",
      loading: false
    };
  },
  methods: {
    // 关闭后跳到传过来的path
    doCancle() {
      this.$emit("dailog-close", "printDialogVisible");
      this.$router.push({ name: this.web_view_reback_path });
    }
  },
  watch: {
    show(item) {
      this.visiable = item;
    },
    web_view_url(newValue, oldValue) {
      this.loading = true;
      this.data_web_view_url = "/";
      setTimeout(() => {
        this.data_web_view_url = newValue;
      }, 200);
      this.loading = false;
    },
  }
};
</script>

组件中定义了4个prop,分别是==show==(控制组件的显示隐藏),==web_view_url==(打印URL),==web_view_reback_path==(关闭打印后的跳转地址),==web_view_error==(是否打印加载失败)

值得注意的是,组件里定义的prop都是单向数据流,只能通过父级组件对齐进行修改,组件本身不能修改props的值,只能修改定义在data里的数据,非要修改,也是通过后面介绍的自定义事件通知父级,由父级来修改;

slot(插槽)

先看下代码

<template>
  <button>
    <slot name="icon"></slot>
    <slot></slot>
  </button>
</template>

这里的节点就是指定的一个插槽的位置,这样在组件内部就可以扩展内容了;

<i-button>
  <i-icon slot="icon" type="checkmark"></i-icon>
  按钮 1
</i-button>

这样,父级内定义的内容,就会出现在组件对应的 slot 里,没有写名字的,就是默认的 slot;

event(事件)

还是先看代码

<template>
  <button @click="handleClick">
    <slot></slot>
  </button>
</template>
<script>
  export default {
    methods: {
      handleClick (event) {
        this.$emit('on-click', event);
      }
    }
  }
</script>

在组件中可以通过$emit触发自定义事件on-click,在父组件通过@on-click来监听

<i-button @on-click="handleClick"></i-button>

组件之间的通信方式

Vue 的组件作用域都是孤立的,不允许在子组件的模板内直接引用父组件的数据。必须使用特定的方法才能实现组件之间的数据传递

1、父子组件之间的通信方式

父组件向子组件的通信方式可以通过props传递: 如果需要从父组件获取 username 的值,就需要

props:{
   username:{
        
   }
}

子组件向父组件传递数据则可以通过event传递:

 methods:{
    handelSwitch(index){
      this.actIndex=index;
      this.$emit("transferTabIndex",this.actIndex)
    }
  }

2、非父子组件之间的通信方式:eventBus

eventBus这种通信方式,针对的是非父子组件之间的通信,它的原理还是通过事件的触发和监听;

但是因为是非父子组件的关系,他们需要有一个中间组件来连接;

我是使用的通过在根组件,也就是#app组件上定义了一个所有组件都可以访问到的组件,具体使用方式如下;

使用eventBus传递数据,我们一共需要做3件事情

  • 1.给app组件添加Bus属性 (这样所有组件都可以通过this.$root.Bus访问到它,而且不需要引入任何文件);
  • 2.在组件1里,this.root.Bus.root.Bus.emit触发事件;
  • 3.在组件2里,this.root.Bus.root.Bus.on监听事件;

3、利用本地化缓存机制

这种通信比较简单,缺点是数据和状态比较混乱,不太容易维护;

通过window.localStorage.getItem(key) 获取数据; 通过window.localStorage.setItem(key,value) 存储数据;

注意用JSON.parse() / JSON.stringify() 做数据格式转换;

实例讲解:銖宝益帮助中心前端组件