vue 单文件探索

原文地址: vue 单文件探索

以 vue 做为开发技术栈的前端开发者,每每会配合前端构建工具,进行项目的工程化管理。好比,你们经常使用的 vue 全家桶 + webpack 的方案进行一些中大型前端项目的开发。配合 webpack 后,vue 的组件化优点更加明显,咱们能够经过单文件的组件化开发方式,在工做实践中搭建前端页面,从而提升开发效率。有这样一个问题:“当咱们在写 vue 单文件时,咱们在写什么?” 不少人可能会这样回答:template 负责模板,javascript 负责逻辑,style 负责样式。当回答到这里时,一个 vue 开发者的世界观基本上算是很明确了。咱们要作的就是在一个单文件组件中写 template、javascript、style。若是仅仅局限于此,显然咱们没法从更好的利用的单文件组件服务咱们的整个开发流程。接下来我将和你们讨论在 vue 单文件开发中的一些方法论的问题。javascript

vue 单文件本质

vue单文件是以特定文件扩展名 .vue 命名的文件。以下所示的代码:css

ListDemo.vuehtml

<template>
    <div class="list-demo">
        <ul>
            <li v-for="item in list" :key="item.key">{{item.value}}</li>
        </ul>
    </div>
</template>

<script>
export default {
    name: 'ListNav',
    data() {
        return {
            list: [
                { key: 'home', value: '首页' },
                { key: 'category', value: '文章分类' },
                { key: 'tags', value: '标签' },
                { key: 'about', value: '关于我' },
                { key: 'links', value: '友情连接'},
            ],
        };
    },
};
</script>

<style>
.list-demo {
    font-size: 14px;
}
</style>

代码中含有 template,script,style。三者的做用此处就不在赘述,如上的结构展现了一个 vue 单文件基本的文件结构。其背后的理念就是一个单文件组件对应了一个功能性组件,该组件的模板,样式,业务逻辑都采用就近维护的思想。从组件的复用性,后期可维护性的角度上来讲,这样的理念都大大的提升了组件化的开发效率。vue 的单文件,既不是 js,也不是 html,也不是 css 文件,这样的文件如何被应用到页面上,这也就是下面将会说到的一个问题,vue 单文件是如何被处理成页面中可用的资源。前端

vue 单文件被处理的流程

vue 单文件配合 webpack 构建工具,在 webpack 中会交由 vue-loader 来处理。以下所示:vue

{
    test: /\.vue$/,
    loader: 'vue-loader',
}

项目中经过 import 或者 require 引入的 vue 单文件,都会通过 vue-loader 处理,vue-loader 在这个过程当中会将模板按照 template、script、style 解析并将处理结果返回,三种不一样类型的文件交由接下来的loader 进行处理。若是该单文件组件在父组件中的 components 声明,则 components 中对应的该项会被插入解析后 script 代码。这个过程从入口文件 main.js 开始,全部涉及的被依赖单文件组件依次经历这样的处理过程。以后全部的组件的实例化将根据业务逻辑中的依赖关系进行,这个过程也是咱们平时在开发中常常用到的一种方式。(这里能够单拉一篇文章详细讲述 vue-loader 的处理流程)java

单文件的经常使用姿式

模板中的组件引用

1、使用方式webpack

组件的拆分和嵌套:web

  • 将具体的业务按照功能以及后期复用性方面的考虑划分红更小的组件
  • 经过一个容器组件(父组件)将小的功能组件(子组件)进行整合

操做手法:父组件中引入子组件,components 中注册,template 中添加相应的组件引用模板element-ui

这种方式也是咱们在进行单文件的开发中经常使用的一种方式,全部组件的实例化,都被隐含在组件的嵌套关系和业务逻辑中。开发者只须要关心组件的引入,在父组件逻辑中注册该组件,并在父组件的模板中以标签的方式引入组件。这个过程当中待引入的组件的实例化时机也能够经过 v-if 指令在业务逻辑中进行控制。api

2、适用场景

大部分场景下咱们均可以经过这样的方式进行组件化的开发。这种模式的有一个特色: 组件的引入经过组件注册和模板中写入对应的组件的标签来完成。模板中经过标签来引入组件这一步必不可少,这个特色在某些业务场景下可能给开发者带来了必定的重复工做量。

API 式的调用

API 式的调用指的是手动建立子组件的实例,业务逻辑中无需引入组件和模板标签占位,在暴露的 API 中控制组件的实例化与显示。

1、使用方式

  • 功能模块提供一个入口 js 来控制该功能模块下单文件实例的全部功能逻辑
  • 其余组件中使用该功能模块时,调用功能模块下的 js,传入部分参数

操做手法:

Confirm.vue

<template>
    <el-dialg
        title="test"
        :visible.sync="visible">
        {{content}}
        <el-button @click="handleCancelClick">cancel</el-button>
        <el-button @click="handleOkClick">ok</el-button>
    </el-dialg>
</template>

<script>
export default {
    name: 'Confirm',
    data() {
        return {
            visible: false,
            content: '这是一个confirm dialog',
            callback: null,
        };
    },
    methods: {
        handleCancelClick() {
            this.callback('cancel');
        },
        handleOkClick() {
            this.callback('confirm');
        },
    },
};
</script>

confirm.js

import Vue from 'vue';
import Confirm from './confirm';

const ConfirmConstructor = Vue.extend(Confirm);

const confirm = (content) => {
    let confirmInstance = new ConfirmConstructor({
        data: {
            content,
        },
    });
    confirmInstance.vm = confirmInstance.$mount();
    confirmInstance.vm.visible = true;
    // 手动插入目的 dom
    document.body.appendChild(confirmInstance.vm.$el);
    confirmInstance.vm.callback = action => {
        return new Promise((resolve, reject) => {
          resolve(action);
        });
    };
    return confirmInstance.vm;
};

如上所示,给出的是一个确认弹框的场景实现。确认弹框在不少用户交互中是一个必须的交互形式。不少组件库也采用上面这种 API 式的组件调用。调用方仅仅经过 api 的调用,就能实现该功能模块的引用。这样就避免了在 template 中经过标签占位的方式引用。实现原理就是手动接管单文件组件的实例化,经过 Vue.extend 得到该组件对应的 Vue 的子类,在暴露给调用的 api 中去实例化这个组件。这个过程当中咱们可能还要完成一些组件数据的注入,逻辑相关以及手动将该组件插入到目的 dom 中。手动的注入 dom 是该种方式的一个很大特色,经过在 api 中动态的注入目的 dom,避免咱们在各个业务组件中调用该功能模块时重复性的在业务组件 template 中手写组件标签。

2、适用场景

  • 功能聚合度高,组件内逻辑简单,输入输出较为单一,好比一些功能较为独立的弹框
  • 一些特殊的自定义指令开发,好比在一些特殊场景的指令,能够复用一些单文件组件,经过在指令的钩子中实例化组件对应的 vue 子类,按照特定的逻辑插入到目的 dom 中(例如:element-ui的v-loading)

区别和共性

共性:经过实例化对应组件完成组件的功能逻辑

区别:实例化的时机和方式不一样。模板式的引入经过组件注册和标签引入的方式来使用单文件组件。标签引入解决了子组件插入的 dom 位置问题,开发者无需关心。API 式的单文件组件使用,在 API 调用时手动实例化组件,须要手动控制插入到目的 dom。

总结

vue 的单文件组件提供了 vue 的组件化开发思路,其本质在导出 vue 的一些关键属性,好比生命周期函数,methods,computed, watch,props等。咱们能够经过上述两种方式来使用单文件组件,目的在于工程内部尽可能减小重复的模板代码,组件解耦。

相关文章
相关标签/搜索