您好,欢迎来到欧得旅游网。
搜索
您的当前位置:首页Vue中SFC和vue-loader的具体分析

Vue中SFC和vue-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时,页面不刷新也可实现内容动态的变化,并保留着程序及其组件的状态。在以下情况下会保持热重载:

    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配置@别名

    相关推荐:

    vue如何利用树形控件z-tree动态添加数据

    Copyright © 2019- ovod.cn 版权所有

    违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

    本站由北京市万商天勤律师事务所王兴未律师提供法律服务