单文件组件
Vue单文件组件是指使用由Vue定义的.vue格式的文件。.vue文件模板如下:
<!-- Vue 只能包含以下三种标签 -->
<!-- 组件的结构 -->
<template>
<!-- ... -->
</template>
<!-- 组件交互相关的代码(数据、方法等等) -->
<script>
export default {
// ...
};
</script>
<!-- 组件的样式 -->
<style>
/* ... */
</style>
其中:
-
<template>:用于定义组件的结构。相当于组件配置中的template配置项。和Html中的
<template>一样,它不会影响页面最终的结构。由于
<template>不会影响页面结构,所以在<template>中还需要定义一个元素作为整个组件的根节点。 -
<script>:定义组件的交互相关的代码。即定义创建组件的JS代码。在
<script>中可以使用Vue.extend()来创建组件。但是由于Vue会在需要的时候帮我们自动调用Vue.extend(),所以Vue.extend()可省略。一般情况下export default组件的配置对象即可。如果要使用
Vue.extend(),需要先引入Vue。 -
<style>:和Html中的<style>一样,都是用于定义样式。 -
.vue注释:.vue中的文件有4个地方可以写注释:-
<template>中:使用Html的注释<!-- 注释内容 -->。 -
<script>中:使用JS的注释// 注释内容或/* 注释内容 */。 -
<style>中:使用CSS的注释/* 注释内容 */。 -
上述范围之外的其它地方:也就是在
<template>、<script>和<style>之外的其它地方可以使用注释。这些注释是属于.vue文件自己的注释,一共有3种注释类型:<!-- 注释内容 --> // 注释内容 /* 注释内容 */也就是说,
<template>、<script>和<style>之外的其它地方可以使用Html、JS和CSS的任何类型的注释。
-
Vue CLI
由于浏览器并不支持直接浏览.vue类型的文件,所以需要将.vue类型的文件编译成浏览器支持的文件类型。而Vue CLI(Vue Command Line Interface,Vue脚手架)可以帮助我们快速地编译.vue。
安装 Vue CLI
Vue CLI需要使用npm安装,请确保你的电脑上已经安装了Node.js。
Vue CLI安装命令如下:
npm install -g @vue/cli
安装完成后直接使用vue命令运行Vue CLI。查看Vue CLI版本以验证是否安装成功:
vue -V
使用 Vue CLI
使用Vue CLI创建一个项目:
vue create vue_demo
接着Vue CLI会让你选择一个默认的配置:
使用键盘的↑或↓去移动选择,然后按下回车即可开始创建。
其中的
babel是用来将ES6的代码转换为ES5。eslint是用来进行语法检查。
出现如下提示表示项目创建成功:
🎉 Successfully created project vue_demo.
👉 Get started with the following commands:
$ cd vue_demo
$ npm run serve
根据提示信息可以知道,进入vue_demo目录之后运行npm run serve可以启动这个项目:
cd vue_demo
npm run serve
启动成功后,项目服务的默认端口是8080,可以访问http://localhost:8080/以浏览Vue CLI为我们创建的HelloWorld这个项目示例。
项目结构
Vue CLI创建好的项目结构一般如下:
vue_demo
├── babel.config.js
├── dist
├── .git
├── .gitignore
├── jsconfig.json
├── package.json
├── package-lock.json
├── public
│ ├── favicon.ico
│ └── index.html
├── README.md
├── src
│ ├── App.vue
│ ├── assets
│ │ └── logo.png
│ ├── components
│ │ ├── Hello.vue
│ │ └── SiteUser.vue
│ └── main.js
└── vue.config.js
在创建好的vue_demo中,有以下这些注意点:
-
.gitignore:排除那些不需要被git所管理的文件或目录。 -
babel.config.js:babel的配置文件。一般来说不需要修改该配置,如果需要修改,可以浏览Babel官网 -
package.json:当前(Node.js)项目的包管理配置文件。其中需要注意一下的是:
{ /* ... */ "scripts": { "serve": "vue-cli-service serve", // 预览项目 "build": "vue-cli-service build", // 构建项目 "lint": "vue-cli-service lint" // 进行语法检查 }, /* ... */ } -
READNE.md:程序说明文档。 -
src:项目源代码文件。在使用默认配置的情况下,名称不可随意更改。src的结构如下所示:main.js:默认的项目入口文件,主要用来创建Vue实例。在使用默认配置的情况下,名称不可随意更改。App.vue:项目中所有组件的根组件。assets:存放项目的静态资源。components:存放项目中(除了App.vue)组件的文件夹。
-
public:存放index.html、favicon.ico等文件。在使用默认配置的情况下,名称不可随意更改。public/index.html是当前项目默认打开的页面。在使用默认配置的情况下,名称不可随意更改。在
index.html中,有一个最重要的东西:<div id="app"></div> -
vue.config.js:Vue CLI的配置文件(可选),与package.json同级。
Vue CLI 入口文件
在main.js中的import Vue from 'vue'和render: h => h(App)语句需要格外注意:
main.js中,使用ES6引入的Vue(即import Vue from 'vue'),是vue.runtime.esm.js。
vue.runtime.esm.js是一个精简版的Vue,其中去除了原本Vue中的模板解析器。所以在main.js的Vue实例中,使用template配置项会因为没有模板解析器而导致无法解析。
有两种方法可以解决该问题:
-
引入完整版的
vue.js:import Vue from 'vue/dist/vue' // 引入 Vue import App from './App.vue' // 引入 App 组件 /* ... */ new Vue({ components: {App}, template: `<App>Hello!</App>`, }).$mount('#app') -
使用
render配置项:import Vue from 'vue' // 引入 Vue import App from './App.vue' // 引入 App 组件 /* ... */ new Vue({ render: h => h(App), }).$mount('#app')render本质是Vue调用的一个函数,它需要接收一个参数createElement这个参数是function类型。createElement()可以帮助我们在页面中创建并渲染元素。例如:import Vue from 'vue' // 引入 Vue // 其实这里也可以使用完整版的 Vue,但是没必要 /* ... */ new Vue({ render(createElement) { console.log('render.'); console.log(typeof createElement); // function return createElement('h2', 'Hello!') }, }).$mount('#app')由于
render中不需要使用this,所以可以使用Lambda表达式() => {}来定义。如上方的解决方案中h => h(App)就是render最简洁的定义方式。使用了
render就无需使用components。
注:在
.vue中依旧是使用<template>和components。也就是说,实例无需使用render。
Vue CLI 配置文件
Vue CLI默认的入口文件就是main.js。并且Vue CLI隐藏了所有webpack相关的配置,若想查看具体的webpack配置,可运行:
vue inspect > output.js
将Vue CLI的webpack相关配置输出到output.js这个文件中(仅用作输出浏览,无法在此更改配置)。
在Vue CLI的webpack相关配置中有这样的内容:
{
/* ... */
entry: {
app: [
'./src/main.js' // 项目入口文件
]
}
}
要修改这些配置内容,需要在vue.config.js中进行修改。它的基本形式如(使用的是common.js的模块化语法):
module.exports = {
/* 选项... */
}
或使用@vue/cli-service提供的defineConfig()帮手函数:
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
/* 选项... */
})
vue.config.js中有一个pages配置项(具体内容可在官方文档中复制):
module.exports = {
/* ... */
pages: {
index: {
// page 的入口
entry: 'src/main.js',
// 模板来源
template: 'public/index.html',
// 在 dist/index.html 的输出
filename: 'index.html',
// 当使用 title 选项时,
// template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
title: 'Index Page',
}
}
}
除了pages配置选项,还有用于关闭语法检查的lintOnSave:
module.exports = {
lintOnSave: false
}
vue.config.js的配置选项可参考 Vue CLI 配置参考。
注:
vue.config.js被修改之后,需要重新运行npm run serve。如果在
vue.config.js中类似这样配置:module.exports = { pages: { index: { /* 空的配置内容 */ } } }那么在启动或者构建项目的时候就会发生错误。因为此时的配置中的
pages.index传递的是一个没有任何属性的对象,而Vue CLI并不会去解析它并为他配上默认的内容。所以在使用
vue.config.js的时候,要么干脆不添加配置选项,使用默认的内容;要么就要按照配置选项的内容进行正确的配置。
Vue 包
Vue的依赖包在node_modules/vue/dist中。其中有这么些版本:
-
.esm:包含.esm的文件代表使用了ES6的模块化语法。使用ES6的模块化语法的版本,浏览器无法直接使用。 -
.min:包含.min就是指压缩版本。 -
完整版:
vue.js:浏览器可以直接使用的完整版本。vue.esm.js:使用了ES6的模块化语法的完整版。
-
runtime:运行时版本,是Vue的精简版本,去除了模板解析器。vue.runtime.jsvue.runtime.min.jsvue.runtime.esm.js
runtime版本不能使用template配置项。需要使用render函数接收到的createElement函数去指定具体内容。 -
common:使用common.js时使用的版本。vue.common.jsvue.common.dev.jsvue.common.prod.jsvue.runtime.common.dev.jsvue.runtime.common.jsvue.runtime.common.prod.js
Vue CLI中
<template>标签配置的模板,是由vue-template-compiler(Vue 模板解析器)来解析。这个vue-template-compiler只能解析.vue中的<template>模板,而不能解析template配置项。
示例
根据以上步骤和信息,将非单文件组件中的site和user定义为单文件组件的形式:
PS:由于使用的Vue CLI版本为5,默认开启语法检查。根据ESLint的官方代码规范,除了
App的其它组件只能以multi-word(多单词)的形式命名。所以下方组件的命名遵循ESLint规范。
multi-word形式选择kebab-case或CameCase都可以。
-
MySite:<template> <div class="my-site"> <h2>网站名称:{{name}}</h2> <h2>网站地址:{{url}}</h2> </div> </template> <script> export default { name: 'MySite', data() { return { name: 'Linner\'s Blog', url: 'blog.linner.asia', } }, }; </script> <style> .my-site { background-color: yellow; } </style> -
SiteUser:<template> <div> <h2>用户姓名:{{name}}</h2> <h2>用户年龄:{{age}}</h2> </div> </template> <script> export default { name: 'SiteUser', data() { return { name: '张三', age: 18, } }, } </script> -
App.vue:<template> <div> <img src="./assets/logo.png" alt="logo"> <MySite/> <hr> <SiteUser/> </div> </template> <script> // 引入组件 import MySite from "./components/MySite.vue"; import SiteUser from './components/SiteUser.vue'; export default { name: 'app', components: { MySite, SiteUser, } } </script>
其它文件暂时不用改动。然后在项目目录下运行npm run serve即可预览。
组件化编码流程
- 拆分静态组件:组件按功能点拆分,命名不要与Html元素冲突。
- 实现动态组件:根据数据被使用的范围,考虑好数据的存放位置。
- 数据只有一个组件在使用:放在组件中即可。
- 数据被一部分组件共同使用:放在这些组件的父组件上(这种方法被称为状态提升,Vue中的数据也可被称为状态)。
- 实现交互:从绑定事件开始。
评论