vue-loader 是一个Webpack的 loader,使用 vue-loader 就可以用 Vue Single-File Component (SFC) 即单文件组件的形式编写一个组件,vue-loader 会将.vue文件转换为 JS模块。

如果在项目开始阶段为前端工程化复杂的配置而困惑,不妨试试使用 IDE 自动构建,推荐使用 WebStorm 新建 Vue 项目,参考 WebStorm 2018 的破解、汉化与设置使用

.vue 单文件组件 (SFC) 规范

1. <template>模板块

一个SFC中最多一个< template >块;
其内容将被提取为字符串传递给 vue-template-compiler ,然后webpack将其编译为js渲染函数,并最终注入到从 <script> 导出的组件中;

2. <script>脚本块

一个SFC最多一个<script>块;
它的默认导出应该是一个 Vue.js 的组件选项对象,也可以导出由 Vue.extend() 创建的扩展对象。
思考:Vue.extend() 中 data 必须是函数,所以在.vue SFC的script中,export中的data是函数

3. <style>样式块

一个 .vue 文件可以包含多个 <style> 标签;
可以使用scope和module进行封装;
具有不同封装模式的多个 <style> 标签可以在同一个组件中混合使用;

4. 自定义语言块

vue-loader 将会使用块名来查找对应的 loader 进行处理,需要配置webpack.config

5. 所有语言块支持 src 导入

导入路径遵循和 webpack 模块请求相同的路径解析规则
// 相对路径需要以../开始
<template src="./template.html"></template>
<style src="./style.css"></style>
<script src="./script.js"></script>

vue-loader 特性概述

  • 支持组件的各个 template,script,style 模块使用其他非默认语言,比如:<style lang=“less”> 使用 less/sass 编译语言,< template >使用 JADE(jade是一个高性能的模板引擎,用JS实现,也有其他语言的实现—php,scala,yuby,python,java,可以供给node 使用)
  • 除了默认的<template>等语言块,还可以加自定义块,然后使用自定义的 loader 处理他们
  • 为组件中的 css 模拟局部作用域,直接<style scope>声明
  • 将 style 和 template 中的静态资源(图片等)当作模块依赖,并通过 webpack loader 处理
  • 在开发模式下的热重载

预处理

Vue 支持各类型的预处理器,这些预处理可以编译语言块,例如 Vue 默认使用 PostCSS 处理 css,你可以用 sass,less,stylus 等, 对于 js 部分 Vue 默认使用 babel 处理,还可以用 coffee、typescript 等,只需要安装相应的 loader 加载器,Vue 会根据语言块的 lang 属性和 webpack 配置的 option rules 推断对应的 loader。

小栗子:css 使用 sass 预处理

$ npm install sass-loader node-sass  --save-dev
// webpack.config.js -> module.rules
{test: /\.sass$/,use: ['vue-style-loader','css-loader',{loader: 'sass-loader',options: {indentedSyntax: true  //sass-loader 默认解析 SCSS 语言}}]
}
<!--  .vue -> style 增加lang属性并赋值 -->
<style lang="sass">
/* write SASS here */
</style>

对于模版<template>的处理方式略有不同,因为大多数 Webpack 模版处理器(比如 pug-loader)会返回模版处理函数,而不是编译的 HTML 字符串,我们可以原始的 pug 替代 pug-loader。

<!--  .vue -> template -->
<template lang="pug">
divh1 Hello world!
</template>

CSS 作用域:scope

当<style>标签带 scope 属性时,创造出 css 的“局部作用域”,css 只作用于当前组件的元素,类似 Shadow Dom 封装。可以在同一个组件中使用 scoped 跟 non-scoped styles,如下所示:

<style>
/* global styles */
</style><style scoped>
/* local styles */
.example {color: red;
}
</style>
<template><div class="example">hi</div>
</template>

vue-loader 处理的 CSS 输出,都是通过 PostCSS 进行作用域重写,PostCSS 处理后如下:

<style>
.example[data-v-f3f3eg9] {color: red;
}
</style><template><div class="example" data-v-f3f3eg9>hi</div>
</template>
  • 使用 scope 时,子组件的根节点将受父组件作用域 CSS 影响

使用 scope 作用域时,父组件的样式不会泄漏到子组件中。 但子组件的根节点将受父级作用域 CSS 和子级作用域 CSS 的影响。 这是为了父级可以设置子组件根元素的样式以进行布局。

  • 使父组件可以使用‘ >>> ’或‘ /deep/ ’ 这种深度选择器作用于子组件
<style scoped>
.a >>> .b { /* ... */ }
</style>

编译为

.a[data-v-f3f3eg9] .b { /* ... */ }
  • 动态生成的 DOM 内容不受 scope style 的影响,但可以使用深度选择器进行样式改变
  • 使用 scope 作用域不能弃用 class 或 id 等

考虑到浏览器渲染各种 CSS 选择器的方式,当使用 scoped 时,选择属性选择器如 p { color: red } 在作用域中会慢很多倍(即当与属性选择器组合时)。如果你使用 class 或者 id 代替,比如 .example { color: red },这样几乎没有性能影响

  • 在递归组件中注意后代选择器

对于带有 .a .b 的 CSS 选择器,如果匹配 .a 的元素包含递归子组件,则该子组件中的所有 .b 将与其匹配。

小思考:在 template 中只包含一个外层节点,不能多个节点并列,这个设计思路遵循父组件可以操作子节点的一个根节点,即使在 CSS 局部作用域下依然有效

CSS 模块模式:module

一个 CSS Module 其实就是一个 CSS 类型的文件,其编写方式与 CSS 相同,但在编译时会编译为 ICSS 低级交换格式。
其默认所有的类名/动画名都在本地作用域,当从 JS 模块导入 CSS 模块时,它会导出包含从本地名称到全局名称的所有映射的一个对象

在 CSS Module 中,所有的 url 和 @import 都是被看成模块依赖,例如 url(./image.png) 会被转换为 require(‘./image.png’)
CSS 模块处理是通过 css-loader,请求的资源可以是在 node_modules 中。

CSS Module 配置

Vue loader 集成了 CSS Module,使用前需要在 css-loader 中设置 modules: true,如下:

// webpack.config.js -> module.rules
{test: /\.css$/,use :['vue-style-loader',{loader: 'css-loader',options: {// enable CSS Modulesmodules: true,// customize generated class nameslocalIdentName: '[local]_[hash:base64:8]'}}]
}    

然后就在<style>中增加 module 属性

<style module>
.red {color: red;
}
</style>

CSS Module 使用

这样 Vue loader 会将 css module 本地对象编译为计算属性注入到组件中,默认值为 $style。template 可以通过动态类绑定使用:

<template><p :class="$style.red">This should be red</p>
</template>

JS 也可以通过 this.$style访问:

<script>
export default {created () {console.log(this.$style.red)// -> "red_1VyoJ-uZ"// an identifier generated based on filename and className.}
}
</script>

为多个 style 自定义标识符

一个 .vue 组件可以有多个<style>,为避免 module 注入样式覆盖,可以通过给属性 module 赋值的方式自定义计算属性的名称:

<style module="a">/* 标识符注入为 a */
</style>
<style module="b">/* 注入为 b */
</style>

结合预处理

CSS Module 还可以在预处理(SASS,LESS等)中使用,在配置 webpack rules 时加上 modules: true,例如:

// webpack.config.js -> module.rules test: /\.scss$/
use[{loader: 'css-loader',options: { modules: true }}]

.vue 中自定义节点/语言块

除了默认的<template>等节点,还可以加自定义节点,并使用自定义的 loader 处理他们;
可以给节点加 lang 属性,此时节点 rule 匹配 lang 的扩展;
如果没有标记 lang,则自定义节点的 name 和 rule 需要在 webpack 中声明。

小栗子:自定义语言块 <myblock>

首先需要 loader。为了将自定义块注入到组件中,自定义一个 loader 如下:

// myblock-loader.js
module.exports = function (source, map) {this.callback(null,`export default function (Component) {Component.options.__myblock = ${JSON.stringify(source)}}`,map)
}

配置到 webpack

// webpack.config.js -> module.rules
{resourceQuery: /blockType=myblock/,loader: require.resolve('./myblock-loader.js')
}

在组件中使用

<!-- ComponentB.vue -->
<template><div>Hello</div>
</template><myblock>
This is the documentation for component B.
</myblock>

组件间的复用

<!-- ComponentA.vue -->
<template><div><ComponentB/><p>{{ myblock }}</p></div>
</template><script>
import ComponentB from './ComponentB.vue';export default {components: { ComponentB },data () {return {myblock: ComponentB.__myblock}}
}
</script>

热重载:不刷新页面的更新

当更改 .vue 的 template 或 style 时,页面不刷新也可实现内容动态的变化,并保留着程序及其组件的状态。在以下情况下会保持热重载:

  1. 编辑组件的<style>,热重载通过 vue-style-loader 自行运行,不会影响应用程序状态
  2. 编辑组件的<template>,实例会重现,这是因为<template>被编译成新的渲染函数,不会产生副作用。
  3. 编辑组件的部分<script>,编辑的实例将销毁后重建,这是因为<script>可能包含产生副作用的生命周期钩子,因此需要“重新加载”以确保一致的行为。如果组件产生全局副作用则需要整页的重新加载。

热加载是默认启动的,当以下情况下关闭:

  • webpack target is node (SSR)
  • webpack 压缩代码
  • 生产模式:process.env.NODE_ENV === 'production'

也可以手动禁用热重载:

// webpack.config.js -> module.rules
{test: /\.vue$/,loader: 'vue-loader',options: {hotReload: false // disables Hot Reload}
}

功能组件

一个简单的.vue组件可以声明为无状态的(没有反应数据)和无实例的(没有此上下文)的功能组件/函数式组件。

vue.js 2.5版本以上,在 template 中加上 functional 属性即可声明:

<template functional></template>

在 script 中的结构为:

Vue.component('my-component', {functional: true,props: { //也可不定义props// ...},render: function (createElement, context) {// createElement, context 为上下文参数// ...}
})

组件加上 functional: true 后,更新渲染函数需要添加 context 参数,故 this.$slots.default 更新为 context.children,this.level 更新为 context.props.level。
功能组件通过 context 对象传递/获取所有的内容,例如:

  • context.props: 包含功能组件的 props 的对象,在vue 2.3+ 如未定义的 props 属性会自动加到组件根元素上;
  • context.children: 包含 VNode 子节点的数组
  • context.slots: 返回 slots 对象的函数
  • context.data: 整个数据对象,作为 createElement 的第二个参数传递给组件
  • context.parent: 指向父组件
  • context.listeners: (2.3.0+) data.on 的别名,包含父级注册事件侦听器的对象。
  • context.injections: (2.3.0+) 包含组件的注入项

由于功能组件只是功能,缺少持久化实例,因此渲染的成本要低得多,也不会出现在 Vue devtools 组件树中;
适用于作为封装组件封装子节点/props/data 后传递给子组件;
功能组件也支持预处理/scope/热重载等。

静态资源 URL 是如何处理的

webpack 配置 module.exports 需要 vue-loader,同时也会有各种静态资源的 loader。当 Vue Loader 编译 SFC 中的<template>时,将会把所有关联的静态资源 url 转为 webpack module 请求。例如:

<img src="../image.png">

会编译为:

createElement('img', {attrs: {src: require('../image.png') // this is now a module request}
})

URL 路径解析规则:

  1. 绝对路径原样保存;
  2. 以“.”开头,则将其解释为相对模块请求,并根据文件系统上的文件夹结构解析;
  3. 以“~”开头,则将其后的内容解析为模块请求,可以在节点模块引用这些内容;
  4. 以“@”开头,则其后的内容也被解释为模块请求,@在 vue-cli 创建的项目中默认指向/ src,可以使用 webpack 配置 @ 别名

官网API:https://vue-loader.vuejs.org/zh/


继续加油哦~ 少年!

【Vue】详解 SFC 与 vue-loader相关推荐

  1. jq的插件 vue中引用_详解如何在 vue 项目里正确地引用 jquery 和 jquery-ui的插件

    本篇文章主要介绍了详解如何在 vue 项目里正确地引用 jquery 和 jquery-ui的插件,具有一定的参考价值,有兴趣的可以了解一下 使用vue-cli构建的vue项目,webpack的配置文 ...

  2. Android Loader 异步加载详解二:探寻Loader内部机制

    Android Loader 异步加载详解二:探寻Loader内部机制 转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/7025991 ...

  3. 详解 30 道 Vue 面试题(建议收藏)

    作者:我是你的超级英雄 https://juejin.im/post/5d59f2a451882549be53b170 前言 本文以前端面试官的角度出发,对 Vue 框架中一些重要的特性.框架的原理以 ...

  4. 详解 30 道 Vue 面试题

    作者:我是你的超级英雄 https://juejin.im/post/5d59f2a451882549be53b170 前言 本文以前端面试官的角度出发,对 Vue 框架中一些重要的特性.框架的原理以 ...

  5. Vue详解及综合案例

    一.Vue简介 1.1 简介 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式的js框架,发布于 2014 年 2 月.与其它大型框架不同的是,Vue 被设计为可以自底 ...

  6. vscode中前端vue项目详解_web前端Vue项目实战-Music

    上篇讲到vue的使用方法,今天这一篇介绍vue的实操,可以大家更加加固去学习web前端vue技术. 第一节 Music项目环境第一部分 本届作业 聊一聊React和Vue的区别 老版本的项目环境如何创 ...

  7. 11_04_第六阶段:大前端进阶||07-Vue详解||P6:Vue绑定事件【观看狂神随笔】

    前序: 1. v-on 可以用v-on指令监听DOM事件,并在触发时运行一些JavaScript代码 参考:jQuery事件 v-on监听事件: 事件有Vue的事件.和前端页面本身的一些事件!我们这里 ...

  8. Vue详解+实战分析

    文章目录 备注 一.Vue简介 简介 MVVM--双向数据绑定模式 其他MVVM实践者 为什么使用Vue.js 两大核心要素 二.Vue开发 引入Vue 快速体验 注释 1.插值表达式 {{}} 注释 ...

  9. 一套史诗级版vue详解!

    文章目录 一.vue官方脚手架 1.初识vue 2.使用vue的方式(2种) 3.搭建vue开发环境 4.vue的重要版本 5.使用@vue/cli进行vue开发环境的构建 6.vue基础知识 1.数 ...

最新文章

  1. Android 中文API (92) —— MenuInflater
  2. .NET Core请求控制器Action方法正确匹配,但为何404?
  3. java2019 数据结构算法面试题_2019年JVM最新面试题,必须收藏它
  4. 特斯拉推出通用钥匙带 官方售价145元
  5. c语言case两个变量的组合,我可以使用带有两个变量的case/switch语句吗?
  6. 为什么到最后还是要 专注于博客写作
  7. SQL文测试数据时,注意对0件的测试!!!【0件时,防止空指针异常!】
  8. 有效解决OneNote同步问题
  9. unity package 包下载不下来
  10. 【Network篇<Day02>】——华为模拟器eNSP、交换机命令、路由器命令
  11. psim扰动观察法编程c语言,一种数字PID控制扰动观察法光伏电池MPPT仿真.doc
  12. 【爬虫实战】国家企业公示网-项目分析
  13. Error processing condition on org.springframework.boot.actuate.autoconfigure.audit.AuditEventsEndpoi
  14. mysql-8.0.28-winx64的安装
  15. MySQL面试试题(五)
  16. 微信再次改版!这个功能终于要下线
  17. 大象装企营销 :市场环境持续低迷,装饰企业该如何破镜重生?
  18. Android 项目工程优化
  19. ZYNQ学习之路16.SDSoC开发环境介绍
  20. 关于RapidIO协议的对齐等问题

热门文章

  1. Win10首次启动出现计算机意外地重启或遇到错误的解决方法
  2. [LeetCode] 3Sum
  3. 苹果全面开放漏洞奖励计划:最高100万美元等你拿
  4. matlab练习程序(图像序列合成视频)
  5. 《简明 PHP 教程》03 第一步
  6. 一起撸个朋友圈吧 (Step6) 评论对齐(点击评论对齐)【下】
  7. 工业互联网联盟发布工业物联网安全框架
  8. 《算法竞赛入门经典》 第二章 循环结构程序设计 习题
  9. 3月国内网民地域分布12强:广东居首 江苏重回第二
  10. 第五周作业:瀑布模型