Vuejs 单文件组件实例详解


Posted in Javascript onFebruary 09, 2018

在之前的实例中,我们都是通过 Vue.component 或者 components 属性的方式来定义组件,这种方式在很多中小规模的项目中还好,但在复杂的项目中,下面这些缺点就非常明显了:

字符串模板:缺乏高亮,书写麻烦,特别是 HTML 多行的时候,虽然可以将模板写在 html 文件中,但是侵入性太强,不利于组件解耦分离。

不支持CSS:意味着当 HTML 和 JavaScript 组件化时,CSS明显被遗漏了

没有构建步骤:限制只能使用 HTML 和 ES5 JavaScript,而不能使用预处理器。

Vuejs 提供的扩展名为 .vue 的 单文件组件 为以上所有问题提供了解决方案。

初识单文件组件

还是利用工欲善其事必先利其器 中的源码,在 src 目录下创建 hello.vue 文件,内容如下:

<template>
 <h2>{{ msg }}</h2>
</template>
<script>
export default {
data () {
return {
msg:'Hello Vue.js 单文件组件~'
}
}
}
</script>
<style>
h2 {
color: green;
}
</style>

然后在 app.js 中引入使用:

// ES6 引入模块语法
import Vue from 'vue';
import hello from './hello.vue';
new Vue({
 el: "#app",
 template: '<hello/>',
 components: {
  hello
 }
});

此时项目是没法运行的,因为 .vue 文件 webpack 是没法是别的,它需要对应的 vue-loader 来处理才行,而且细心的朋友会发现 hello.vue 中用到了 ES6 语法,此时就需要用到相应的语法转化 loader 将 ES6 转化成主流浏览器兼容的 ES5 语法,这里就需要用到官方推荐的 babel 工具了。先安装需要的 loader :

# hello.vue 文件中使用了 css,所以需要 css-loader 来处理,vue-loader 会自动调用
npm install vue-loader css-loader babel-loader babel-core babel-preset-env --save-dev

有的人疑惑只是使用 babel-loader 为什么还需要安装后面这么多工具呢,这是因为很多工具都是独立的, loader 只是为了配合 webpack 使用的桥梁,而这里 babel-core babel-preset-env 才是实现 ES6 到 ES5 的核心。

我们再修改 webpack.config.js 配置如下:

module.exports = {
 // ...
 module: {
  // 这里用来配置处理不同后缀文件所使用的loader
  rules: [
   {
    test: /.vue$/,
    loader: 'vue-loader'
   },
   {
    test: /.js$/,
    loader: 'babel-loader'
   }
  ]
 }
}

对于 babel 的配置,我们还需在项目根目录下刚创建 .babelrc 文件来配置 Babel presets 和 其他相关插件,内容如下:

{
 "presets": [ "env" ]
}

但是虽然虽然都配置好了,项目还是还是会报错,报如下错误:

ERROR in ./src/hello.vue
Module build failed: Error: Cannot find module 'vue-template-compiler'

有人就不高兴了,明明是按照官方提示安装了依赖,并正确的进行配置,为什么还是会报错呢?遇到错误不要怕,先阅读下错误是什么,很容易发现,是因为 Cannot find module 'vue-template-compiler' ,这是因为 vue-loader 在处理 .vue 文件时,还需要依赖 vue-template-compiler 工具来处理。

刚开始我不知道官方为什么没有直接告诉用户需要安装这个依赖,通过阅读 vue-loader 才明白其 package.json 文件中是将 vue-template-compilercss-loader 作为 peerDependencies ,而 peerDependencies 在安装的时候,并不会自动安装(npm@3.0+),只会给出相关警告,所以这个需要我们手动安装的,当然在 .vue 文件中如果需要写 CSS,也必须用到 css-loader ,这个也是在 peerDependencies 中。相关讨论: https://github.com/vuejs/vue-loader/issues/1158

知道问题了,直接安装下就可以了:

npm install vue-template-compiler css-loader --save-dev

再次运行项目,页面中出现了我们的内容,并没报错,ok,大功告成~

使用预处理器

我们已经学会在 .vue 中写 css 了,那么如果使用 sass 预处理器呢?首先安装上篇文章中提到的模块:

npm install sass-loader node-sass --save-dev

配置只需两步:

修改 webpack.config.js 中 vue-loader 配置

module.exports = {
 // ...
 module: {
  // 这里用来配置处理不同后缀文件所使用的loader
  rules: [
   {
    test: /.vue$/,
    loader: 'vue-loader',
    options: {
     loaders: {
      // 这里也可以使用连写方式,但是不利于自定义话参数配置
      // scss: 'vue-style-loader!css-loader!sass-loader'
      scss: [
       {
        loader: 'vue-style-loader'
       },
       {
        loader: 'css-loader'
       },
       {
        loader: 'sass-loader'
       }
      ]
     }
    }
   },
   // ...
  ]
 }
}

给 .vue 文件中的 style 标签,添加 lang="scss" 属性。

配置完后,就可以再 .vue 文件中,愉快地编写 sass 语法了。

加载全局设置文件

实际开发中,我们在编写 sass 文件时,经常会将全局的 scss 变量提取出来,放到一个单独的文件中,但是这样就有个问题,每个需要用到的组件,都需要手动 @import './styles/_var.scss' 进来,非常不友好。插件 sass-resources-loader 就很好地帮我们解决这个问题,先安装一下:

npm install sass-resources-loader --save-dev

然后修改 webpack.config.js 文件中 vue-loader 相关配置:

// ...
{
 test: /.vue$/,
 loader: 'vue-loader',
 options: {
  loaders: {
   scss: [
    {
     loader: 'vue-style-loader'
    },
    {
     loader: 'css-loader'
    },
    {
     loader: 'sass-loader'
    },
    // 看这里,看这里,看这里
    {
     loader: 'sass-resources-loader',
     options: {
      // 这里的resources 属性是个数组,可以放多个想全局引用的文件
      resources: [resolve('./src/styles/_var.scss')]
     }
    }
   ]
  }
 }
}
// ...

配置就完成了,我们再来测试下。

在 src 目录下分别创建 hello1.vue 和 hello2.vue 文件:

<!-- hello1.vue -->
<template>
 <h1>{{ msg }}</h1>
</template>
<script>
export default {
name:'hello1',
data () {
return {
msg:'Hello Vue.js 单文件组件~'
}
}
}
</script>
<stylelang="scss">
h1 {
color: $green;
}
</style>

<!-- hello2.vue -->
<template>
 <h1>{{ msg }}</h1>
</template>
<script>
export default {
name:'hello2',
data () {
return {
msg:'Hello Vue.js 单文件组件~'
}
}
}
</script>
<stylelang="scss">
h1 {
color: $red;
}
</style>

然后创建一个 styles 目录,并在其中新建存放全局变量的文件 _var.scss :

$green: rgb(41, 209, 41);
$red: rgb(177, 28, 28);

接下来,在 app.js 中引用两个组件:

import Vue from 'vue';
import hello1 from './hello1.vue';
import hello2 from './hello2.vue';
new Vue({
 el: "#app",
 template: '<div><hello1/><hello2/></div>',
 components: {
  hello1,
  hello2
 }
});

重新运行项目就可以了。

有作用域的 style

单文件组件中为我们提供了一个非常便利的功能,就是当 style 标签添加 scoped 属性时,标签内的样式将只作用于当前组件中的元素。

接着上面的例子,运行后会发现 hello1.vue 中的 h1 颜色并不是想要的 $green 色,而是被 hello2.vue 中的样式覆盖了。于是分别在 hello1.vue 和 hello2.vue 的 style 标签上添加 scoped 属性,如下:

<!-- hello1.vue -->
<stylelang="scss"scoped>
h1 {
color: $green;
}
</style>
<!-- hello2.vue -->
<stylelang="scss"scoped>
h1 {
color: $red;
}
</style>

这样一来我们的两个 h1 标签颜色都显示正常了。

自定义块

在编写某些开源组件时,有时候我们需要同时维护多个组件和组件说明,但是每次修改就要同时修改 .vue 和 .md 文件,相当麻烦。 .vue 文件的 自定义语言块 功能,就允许我们将 markdown 说明同时写进 .vue 文件中,然后通过插件将其说明部分单独提取到相应的 .md 文件中,这样就可以同时维护说明文档和组件功能了。

比如我们将 hello1.vue 文件修改如下:

<docs>
 # 标题
  这是标题内容,[仓库地址](https://github.com/yugasun/You-Dont-Know-Vuejs)
 ## 子标题
  这是子标题内容
</docs>
<template>
 <h1>{{ msg }}</h1>
</template>
<script>
export default {
name:'hello1',
data () {
return {
msg:'Hello Vue.js 单文件组件~'
}
}
}
</script>
<stylelang="scss"scoped>
h1 {
color: $green;
}
</style>

然后修改 webpack.config.js 配置:

const path = require('path');
// 引入相关插件
const ExtractTextPlugin = require('extract-text-webpack-plugin');
function resolve(dir){
 return path.resolve(__dirname, dir);
}
module.exports = {
 // 入口文件
 entry: './src/app.js',
 // 编译输出文件
 output: {
  path: resolve('./'),
  filename: 'build.js'
 },
 resolve: {
  alias: {
   // 因为我们这里用的是 require 引入方式,所以应该使用vue.common.js/vue.js/vue.min.js
   'vue$': 'vue/dist/vue.common.js'
  }
 },
 devServer: {
  // 这里定义 webpack-dev-server 开启的web服务的根目录
  contentBase: resolve('./')
 },
 module: {
  // 这里用来配置处理不同后缀文件所使用的loader
  rules: [
   {
    test: /.vue$/,
    loader: 'vue-loader',
    options: {
     loaders: {
      scss: [
       {
        loader: 'vue-style-loader'
       },
       {
        loader: 'css-loader'
       },
       {
        loader: 'sass-loader'
       },
       {
        loader: 'sass-resources-loader',
        options: {
         resources: [resolve('./src/styles/_var.scss')]
        }
       }
      ],
      docs: ExtractTextPlugin.extract('raw-loader')
     }
    }
   },
   {
    test: /.js$/,
    loader: 'babel-loader'
   }
  ]
 },
 plugins: [
  new ExtractTextPlugin('docs.md')
 ]
}

这里用到了 extract-text-webpack-plugin 导出 text 插件,和 raw-loader ,分别都安装下就行。

然后运行构建命令 npm run build ,等运行结束,根目录下会同时生成一个 docs.md 文件,这就是我们想编写的说明文档。

点击查看源码:https://github.com/yugasun/You-Dont-Know-Vuejs/tree/master/chapter2/2

总结

以上所述是小编给大家介绍的Vuejs 单文件组件实例详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
js检测客户端不是firefox则提示下载
Apr 07 Javascript
JavaScript 对象的属性和方法4种不同的类型
Mar 19 Javascript
jquery中邮箱地址 URL网站地址正则验证实例代码
Sep 15 Javascript
JavaScript中创建对象和继承示例解读
Feb 12 Javascript
jQuery中toggleClass()方法用法实例
Jan 05 Javascript
JavaScript使用shift方法移除素组第一个元素实例分析
Apr 06 Javascript
js显示当前日期时间和星期几
Oct 22 Javascript
jQuery Ajax 上传文件处理方式介绍(推荐)
Jun 30 Javascript
web 屏蔽BackSpace键实例代码
Dec 24 Javascript
BootStrap注意事项小结(五)表单
Mar 10 Javascript
JS异步加载的三种实现方式
Mar 16 Javascript
JS实现数组去重,显示重复元素及个数的方法示例
Jan 21 Javascript
vue-lazyload图片延迟加载插件的实例讲解
Feb 09 #Javascript
详解js正则表达式验证时间格式xxxx-xx-xx形式
Feb 09 #Javascript
在Vue中使用highCharts绘制3d饼图的方法
Feb 08 #Javascript
vue中使用ueditor富文本编辑器
Feb 08 #Javascript
React Native自定义控件底部抽屉菜单的示例
Feb 08 #Javascript
vue 使用ref 让父组件调用子组件的方法
Feb 08 #Javascript
Vuejs 2.0 子组件访问/调用父组件的方法(示例代码)
Feb 08 #Javascript
You might like
thinkPHP3.1验证码的简单实现方法
2016/04/22 PHP
JS下拉框内容左右移动效果的具体实现
2013/07/10 Javascript
js简单实现根据身份证号码识别性别年龄生日
2013/11/29 Javascript
jQuery实现数字加减效果汇总
2014/12/16 Javascript
JavaScript中的console.group()函数详细介绍
2014/12/29 Javascript
JavaScript使用concat连接数组的方法
2015/04/06 Javascript
javascript函数式编程程序员的工具集
2015/10/11 Javascript
javascript判断复选框是否选中的方法
2015/10/16 Javascript
js实现跨域的几种方法汇总(图片ping、JSONP和CORS)
2015/10/25 Javascript
常用原生JS兼容性写法汇总
2016/04/27 Javascript
Javascript OOP之面向对象
2016/07/31 Javascript
AngularJS ui-router (嵌套路由)实例
2017/03/10 Javascript
AngularJS实现的select二级联动下拉菜单功能示例
2017/10/25 Javascript
微信小程序获取用户信息并保存登录状态详解
2019/05/10 Javascript
JS实现获取当前所在周的周六、周日示例分析
2019/05/11 Javascript
VUE 自定义组件模板的方法详解
2019/08/30 Javascript
node crawler如何添加promise支持
2020/02/01 Javascript
js里面的变量范围分享
2020/07/18 Javascript
vue-preview动态获取图片宽高并增加旋转功能的实现
2020/07/29 Javascript
微信小程序wx.getUserInfo授权获取用户信息(头像、昵称)的实现
2020/08/19 Javascript
用Python的线程来解决生产者消费问题的示例
2015/04/02 Python
Python记录详细调用堆栈日志的方法
2015/05/05 Python
Python使用PDFMiner解析PDF代码实例
2017/03/27 Python
Python基于jieba库进行简单分词及词云功能实现方法
2018/06/16 Python
python 将print输出的内容保存到txt文件中
2018/07/17 Python
python实现电子产品商店
2019/02/26 Python
Keras模型转成tensorflow的.pb操作
2020/07/06 Python
Python抓包并解析json爬虫的完整实例代码
2020/11/03 Python
英国综合网上购物商城:The Hut
2018/07/03 全球购物
伦敦新晋轻奢耳饰潮牌:Tada & Toy
2020/05/25 全球购物
ktv中秋节活动方案
2014/01/30 职场文书
家长对孩子的感言
2014/03/10 职场文书
合作经营协议书
2014/04/17 职场文书
乡镇三严三实学习心得体会
2014/10/13 职场文书
2016大学生优秀志愿者事迹材料
2016/02/25 职场文书
SpringCloud Alibaba 基本开发框架搭建过程
2021/06/13 Java/Android