愿你坚持不懈,努力进步,进阶成自己理想的人

—— 2017.09, 写给3年后的自己

vue-loader使用总结

vue-loader是用来加载.vue文件的,下面来总结一下vue单文件组件以及vue-loader的用法

一、Vue组件细则

.vue是一个自定义的文件类型,它采用类html语法来描述一个Vue组件。每个.vue组件包含有三种顶级的语言块:<template><style><script>,此外,我们还可以添加自定义的块:

<template>
    <div class="example">{{ msg }}</div>
</template>

<script>
export default {
    data() {
        return {
            msg: 'Hello, world!'
        }
    }
}
</script>

<style>
.example {
    font-weight: bold;
}
</style>

vue-loader会解析文件,提取每个语言块,如果有必要的话,还会交给其他loader处理,最后则组装成一个CommonJS模块,通过module.exports来导出一个Vue.js组件对象。
我们可以通过指定lang属性来指定其他语言(如sass、jade):

<style lang="sass">
/* ... */
</style>

语言块

1、<template>块:每个.vue文件最多只能包含一个,其内容会被提取为字符串用于template选项
2、<script>块:每个.vue文件最多只能包含一个。如果检测到babel-loaderbuble-loader,那么会自动支持ES6语法。注意:

  • 脚本在类CommonJS环境中执行,所以可以require()其他依赖。如果支持ES6,那么可以使用ES6的模块语法
  • 脚本必须导出Vue.js组件对象,或者Vue.extend()创建的扩展对象

3、<style>块:可以包含多个。可以指定scoped属性或者module属性,默认情况下:会使用style-loader提取内容,并通过<style>标签动态加入到文档的<head>中(可以使用webpack的ExtractTextPlugin来提取到单个文件中)

src导入

如果不习惯一个文件里同时包含有htmlcssJavaScript,那么我们可以使用语言块的src属性来把扩展文件引入到组件中,如:

<template src="./template.html"></template>
<style src="./style.css"></style>
<script src="./script.js"></script>

注意:src导入遵循的是和require()一样的规则,所以相对路径需要以./开始


二、特性

1、ES6支持

当项目中配置了babel-loader或者buble-loader后,vue-loader会使用他们处理所有 .vue文件中的<script>部分,允许我们在 Vue 组件中使用ES6,如:

<script>
import ComponentA from './ComponentA.vue'
import ComponentB from './ComponentB.vue'

export default {
    components: {
        ComponentA,
        ComponentB
    }
}
</script>

这种写法下,Vue会自动将驼峰式转为连字符式,如ComponentA转为component-a,所以可以在template中使用<component-a>
.vue文件中的<template>会自动编译为JavaScript渲染函数,然后通过自定义构建的Buble来支持ES6,所以对于以下的例子:

<div :class="[{active: active}, isButton ? prefix + '-button': null]">

可以简写为:

<div :class="[{active, [`${prefix}-button`]: isButton]">

vue 2.1.0版本及以上,我们还可以在v-for或者scoped slots中使用解构赋值,如:

<li v-for="{id, text} in items">
    {{id}} {{text}}
</li>

<my-component>
    <template scope="{id, text}">
        <span>{{id}} {{text}}</span>
    </template>
</my-component>

2、CSS作用域

如果<style>标签中带有scoped属性,那么这个标签中的CSS只能作用于当前组件中的元素,如:

<style scoped>
.example {
    color: red;
}
</style>
<template>
    <div class="example">Hello</div>
</template>

这是因为,它会被转化为如下的形式:

<style>
.example[data-v-f3f3eg9] {
    color: red;
}
</style>
<template>
    <div class="example" data-v-f3f3eg9>Hello</div>
</template>

注意:

  • 可以同时使用局部样式和全局样式(不带scoped
  • 子组件的根节点将同时受父组件和子组件作用域CSS的影响
  • Partials 不受作用域样式影响
  • CSS 作用域不能代替 classes,这是因为作用域的实现是结合起属性选择器的,这种情况下,会比使用class来约定命名空间慢很多
  • 在递归组件中小心使用后代选择器! 对于带有选择器 .a .b 的CSS 规则,如果元素 .a 包含递归子组件,所有的子组件中的 .b 会被匹配

3、CSS模块

<style>标签指定module属性可以模拟CSS作用域,这种情况下,会为css-loader打开CSS模块模式,生成的CSS对象将为组件注入一个$style计算属性,所以可以这么使用:

<style module>
.red {
    color: red;
}
.bold {
    font-weight: bold;
}
</style>

在模板中:

<template>
    <p :class="$style.red">Hello, world</p>
</template>

这种情况下,将会生成得到形如:

<template>
    <p class="C-YXGwO4CZHdg_W7q5Y_2_0">Hello, world</p>
</template>

由于这是个计算属性,所以我们可以像对待普通计算属性那样子来使用它,并且在js中使用也是没问题的:

export default {
    created() {
        console.log(this.$style.red);
    }
}

vue-loader里使用的对css-loader默认的query为:

{
    modules: true,
    importLoaders: true,
    localIdentName: '[hash:base64]'
}

可以在webpack里对vue-loader进行配置来改变css-loader的配置,如:

module: {
    rules: [
        {
            test: /\.vue$/,
            loader: 'vue-loader',
            options: {
                cssModules: {
                    localIdentName: '[path][name]---[local]---[hash:base64:5]',
                    camelCase: true
                }
            }
        }
    ]
}

4、热重载

"热重载"不是修改文件的时候简单重新加载页面。而是:当修改 .vue 文件时,所有该组件的实例会被替换,并且不需要刷新页面。甚至可以保持应用程序和被替换组件的当前状态,当你调整模版或者修改样式时,这极大的提高了开发体验。


待续...