浅谈vue 单文件探索

在很多Vue项目中,我们使用 Vue.component 来定义全局组件,紧接着用new Vue({ el: '#container '}) 在每个页面内指定一个容器元素。

这种方案在只是使用 JavaScript 增强某个视图的中小型项目中表现得很好。然而在更复杂的项目中,或者当你的前端完全采用 JavaScript 驱动的时候,以下弊端就显现出来:

  • 全局定义(Global definitions) 强制要求每个 component 中的命名不得重复
  • 字符串模板(String templates) 缺乏语法高亮,在 HTML 有多行的时候,需要用到丑陋的\
  • 不支持CSS(No CSS support) 意味着当 HTML 和 JavaScript 组件化时,CSS 明显被遗漏
  • 没有构建步骤(No build step) 限制只能使用 HTML 和 ES5 JavaScript, 而不能使用预处理器,如 Pug (formerly Jade) 和 Babel

文件扩展名为 .vue 的 single-file components(单文件组件) 为以上所有问题提供了解决方法,并且还可以使用 Webpack 或 Browserify 等构建工具。

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

vue 单文件本质

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

ListDemo.vue

<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 来处理。如下所示:

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

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

单文件的常用姿势

模板中的组件引用

一、使用方式

组件的拆分和嵌套:

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

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

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

二、适用场景

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

API 式的调用

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

一、使用方式

  • 功能模块提供一个入口 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 中手写组件标签。

二、适用场景

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

区别和共性

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

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

总结

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 关于vue单文件中引用路径的处理方法

    前言 Vue 的单文件组件在使用 Vue 时非常常用,而在vue单文件的开发过程中,在单文件模版中可能会涉及到文件路径的处理,比如 <img>, style 中的 background 的处理等.下文中讨论了几种不同场景下的 <img> 的 src 处理,解释了在使用 vue+webpack 的开发过程中如何正确的引用静态资源(比如图片的处理). 如下所示,在下面的单文件组件中给出了不同场景下引用图片路径的示例(图片静态资源存放在 src/assets/small.png ): &

  • Vuejs 单文件组件实例详解

    在之前的实例中,我们都是通过 Vue.component 或者 components 属性的方式来定义组件,这种方式在很多中小规模的项目中还好,但在复杂的项目中,下面这些缺点就非常明显了: 字符串模板:缺乏高亮,书写麻烦,特别是 HTML 多行的时候,虽然可以将模板写在 html 文件中,但是侵入性太强,不利于组件解耦分离. 不支持CSS:意味着当 HTML 和 JavaScript 组件化时,CSS明显被遗漏了 没有构建步骤:限制只能使用 HTML 和 ES5 JavaScript,而不能使用

  • Vue 单文件中的数据传递示例

    Vue 的单文件组件在使用 Vue 时非常常用,所以我们也会经常遇到组件之间需要传递数据的时候,大致分为三种情况: 父组件向子组件传递数据,通过 props 传递数据. 子组件向父组件传递数据,通过 events 传递数据. 两个同级组件之间传递数据,通过 event bus 传递数据. 文档中也已经详细的说明了各种情况下的解决方法,但是现在我在还没有阅读多少文档的情况下,没有找到有单文件组件方面的具体书写方式,智商和理解能力有限的情况下,自己尝试了一下,最后发现其实是一样的.所以这篇文章其实是

  • Vuejs实现带样式的单文件组件新方法

    本文实例为大家分享了Vuejs实现单文件组件的方法,供大家参考,具体内容如下 代码如下: example.html <script src="vue.js"></script> <div id="example"> <h3>Vue component<h3> <counter></counter> <counter></counter> </div>

  • jquery加载单文件vue组件的方法

    本文为大家分享了jquery加载单文件vue组件的方法,供大家参考,具体内容如下 /**注册组件 */ function registerComponent(name){ dm[name] = {}; Vue.component(name + '-component', function(resolve, reject){ $.get('./modules/' + name + '.vue').then(function(rv){ var temp = rv.match(/<template[^

  • Vue单文件组件的如何使用方式介绍

    在很多 vue项目中,我们使用 vue.component 来定义全局组件,紧接着用 new vue(el: ")在每个页面内指定一个容器元素 这种方式在很多中小规模的项目中运作的很好,在这些项目里 JavaScript 只被用来加强特定的视图. 但挡在更复杂的项目中,或者你的前端完全由 javascript 驱动的时候,下面这些缺点将变得非常明显: 全局定义 (global definitions)强制要求每个 component 中的命名不能重复 字符串模板 (string template

  • 基于Vue单文件组件详解

    本文将详细介绍Vue单文件组件 概述 在很多 Vue 项目中,使用 Vue.component 来定义全局组件,紧接着用 new Vue({ el: '#container '}) 在每个页面内指定一个容器元素. 这种方式在很多中小规模的项目中运作的很好,在这些项目里 JavaScript 只被用来加强特定的视图.但当在更复杂的项目中,或者前端完全由 JavaScript 驱动的时候,下面这些缺点将变得非常明显: 1.全局定义 (Global definitions) 强制要求每个 compon

  • Vue单文件组件基础模板小结

    背景 相信大家在使用Vue开发项目时,基本都是以单文件组件的形式开发组件的,这种方式好处多多: 1.代码集中,便于开发.管理和维护 2.可复用性高,直接将vue文件拷贝到新项目中 我暂时就想到这两点,童鞋们可以在评论里帮我补充:因为有这么多优点,所以决定有必要将vue组件的常用配置项提炼出来,形成一个组件模板,方便日后项目开发复用 <template> <div> <h1>{{title}}</h1> <ChildComponents></

  • vuejs 单文件组件.vue 文件的使用

    vuejs 自定义了一种.vue文件,可以把html, css, js 写到一个文件中,从而实现了对一个组件的封装, 一个.vue 文件就是一个单独的组件.由于.vue文件是自定义的,浏览器不认识,所以需要对该文件进行解析. 在webpack构建中,需要安装vue-loader 对.vue文件进行解析.在 sumlime 编辑器中,我们 书写.vue 文件,可以安装vue syntax highlight 插件,增加对文件的支持. 用vue-cli 新建一个vue项目,看一下.vue文件长什么样

  • 浅谈vue 单文件探索

    在很多Vue项目中,我们使用 Vue.component 来定义全局组件,紧接着用new Vue({ el: '#container '}) 在每个页面内指定一个容器元素. 这种方案在只是使用 JavaScript 增强某个视图的中小型项目中表现得很好.然而在更复杂的项目中,或者当你的前端完全采用 JavaScript 驱动的时候,以下弊端就显现出来: 全局定义(Global definitions) 强制要求每个 component 中的命名不得重复 字符串模板(String template

  • 浅谈Vue-cli单文件组件引入less,sass,css样式的不同方法

    vue-cli中已经内置配置好了sass 以及lass的配置.如果需要的话直接下载两个模块就可以了,webpack它会根据 lang 属性自动用适当的加载器去处理. 如果需要使用sass,则安装: npm install node-sass --save-dev npm install sass-loader --save-dev 如果需要使用less,则安装: npm install less --save-dev npm install less-loader --save-dev sass

  • 浅谈Vue单页面做SEO的四种方案

    目录 1.Nuxt 服务端渲染应用部署 (SSR服务器渲染) 优势: 不足:(开发中遇到的坑) 2.Nuxt 静态应用部署 优势: 不足: 3.预渲染prerender-spa-plugin 优势: 不足: 4.Phantomjs 针对爬虫做处理 优势: 不足: 总结 众所周知,Vue SPA单页面应用对SEO不友好,当然也有相应的解决方案,通过查找资料,大概有以下4种方法.(本人只用过第一,第三种方案) 1.Nuxt 服务端渲染应用部署 (SSR服务器渲染) 关于服务器渲染:Vue官网介绍 ,

  • 浅谈vue单页面中有多个echarts图表时的公用代码写法

    html中: <div class="charts1"/> <div class="charts2"/> <div class="charts3"/> <div class="charts4"/> <div class="charts5"/> <div class="charts6"/> <div class=

  • 浅谈VUE单页应用首屏加载速度优化方案

    单页应用会随着项目越大,导致首屏加载速度很慢!!!以下给出在下知道的几种优化方案 使用CDN资源,减小服务器带宽压力 路由懒加载 将一些静态js css放到其他地方(如OSS),减小服务器压力 按需加载三方资源,如iview,建议按需引入iview中的组件 使用nginx开启gzip减小网络传输的流量大小 webpack开启gzip压缩 若首屏为登录页,可以做成多入口,登录页单独分离为一个入口 使用CDN资源,减小服务器带宽压力 在index.html中引入cdn资源 ... <body> &

  • 浅谈vue同一页面中拥有两个表单时,的验证问题

    问题:如果vue的同一个页面拥有两个表单.验证第一个表单时没有通过就切换到第二个,那么第二个表单会出现验证错误的信息 我们可以通过为两个表单添加ref属性 之后在通过调用resetFields()方法来解决问题 代码如下 <el-form :model="form" :rules="rules" ref="form" label-width="100px"> this.$refs["form"]

  • 浅谈Vue+Ant Design form表单的一些坑

    目录 设置默认值的坑 自定义 v-decorator 组件的坑 最近在用 vue + ant 写项目发现 from 组件的坑还是比较多的 设置默认值的坑 控制台报 Warning: You cannot set a form field before rendering a field associated with the value. You can use getFieldDecorator(id, options) instead v-decorator="[id, options]&q

  • 浅谈Vue.js

    vue.js的总体评价"简单却不失优雅,小巧而不乏大匠" Vue.js简介 Vue.js的作者为Evan You(尤雨溪),任职于Google Creative Lab,虽然Vue是一个个人项目,但在发展前景上个人认为绝不输于Google的AngularJs,下面我会将Vue与Angular(Angular 1.0+版本)做一些简单的比较. Vue的主要特点就和它官网(http://cn.vuejs.org/)所介绍的那样: (1) 简洁 (2) 轻量 (3)快速 (4) 数据驱动 (

  • 浅谈vue首屏加载优化

    本文介绍了浅谈vue首屏加载优化,分享给大家,具体如下: 库使用情况 vue vue-router axios muse-ui material-icons vue-baidu-map 未优化前 首先我们在正常情况下build 优化 1. 按需加载 当前流行的UI框架如iview,muse-ui,Element UI都支持按需加载,只需稍微改动一下代码. 修改前: import MuseUI from 'muse-ui' import 'muse-ui/dist/muse-ui.css' imp

  • 浅谈Vue 函数式组件的使用技巧

    什么是函数式组件 没有管理任何状态,也没有监听任何传递给它的状态,也没有生命周期方法,它只是一个接受一些 prop 的函数.简单来说是 一个无状态和无实例的组件 基本写法: Vue.component('my-component', { functional: true, // Props 是可选的 props: { // ... }, // 为了弥补缺少的实例 // 提供第二个参数作为上下文 render: function(createElement, context) { // ... }

随机推荐