您好,欢迎访问一九零五行业门户网

Vue中SFC和vue-loader的具体分析

本篇文章给大家分享的是关于vue中sfc和vue-loader的具体分析,内容很不错,有需要的朋友可以参考一下,希望可以帮助到大家。
官网:https://vue-loader.vuejs.org/zh/
vue-loader是一个webpack的loader,简单来说是将vue文件转换为js模块。在监测到babel-loader或者buble-loader配置时,自动支持es2015;
使用vue-loader就可以用vue single-file component (sfc)即单文件组件的形式编写一个组件。
.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">p  h1 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>  <p class="example">hi</p></template>
vue-loader处理的css输出,都是通过postcss进行作用域重写,postcss处理后如下:
<style>.example[data-v-f3f3eg9] {  color: red;}</style><template>  <p class="example" data-v-f3f3eg9>hi</p></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中。
vue loader中的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 modules        modules: true,        // customize generated class names        localidentname: '[local]_[hash:base64:8]'      }    }  ]}
然后就在<style>中增加module属性
<style module>.red {  color: red;}</style>
使用这样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>  <p>hello</p></template><myblock>this is the documentation for component b.</myblock>
组件间的复用
<!-- componenta.vue --><template>  <p>    <componentb/>    <p>{{ myblock }}</p>  </p></template><script>import componentb from './componentb.vue';export default {  components: { componentb },  data () {    return {      myblock: componentb.__myblock    }  }}</script>
热重载:不刷新页面的更新当更改.vue的template或style时,页面不刷新也可实现内容动态的变化,并保留着程序及其组件的状态。在以下情况下会保持热重载:
编辑组件的<style>,热重载通过vue-style-loader自行运行,不会影响应用程序状态
编辑组件的<template>,实例会重现,这是因为<template>被编译成新的渲染函数,不会产生副作用。
编辑组件的部分<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路径解析规则:绝对路径原样保存;
以“.”开头,则将其解释为相对模块请求,并根据文件系统上的文件夹结构解析;
以“~”开头,则将其后的内容解析为模块请求,可以在节点模块引用这些内容;
以“@”开头,则其后的内容也被解释为模块请求,@在vue-cli创建的项目中默认指向/ src,可以使用webpack配置@别名
相关推荐:
vue如何利用树形控件z-tree动态添加数据
vue父子组件之间是如何进行传值的
以上就是vue中sfc和vue-loader的具体分析的详细内容。
其它类似信息

推荐信息