截止上一节,我们学习了webpack的四大核心思想:入口(entry)、出口(output)、加载器(loaders)、插件(plugins),并且初步创建了一个可以在本地端口运行的工程。接下来我们继续探讨学习.vue单文件组件的使用和编译。
众所周知,Vue.js官网提供了组件的三种使用方法:
字符串 (例如:template: '...')
<script type="text/x-template">
单文件组件 (.vue)
- 第一种方法使用起来需要在js内拼接DOM字符串,尤其是用" \ "换行的时候。
- 第二种方法可以用于模板特别大的 demo 或极小型的应用,但是其它情况下请避免使用,因为这会将模板和该组件的其它定义分离开。这个方法也可以
异步调用
。 - 本篇着重介绍第三种方法,它是构建SPA常用的形式。
.vue文件的构成
一个.vue文件包括三部分,<templtae>、<script>、<style>,可以没有<style>,在根目录下创建app.vue文件,快速建立vue预制模板
,如下:
下面解读一下各部分代表的意义:
- <template></template>之间的代码就是该组件的模板html,和正常书写html一样,不需要引号和换行符。
- <script></script>大家都很熟悉,书写js代码,.vue文件通常使用ES6处理该组件的业务逻辑。
- <style></style>之间是css代码,示例中的<style>标签使用了scoped属性,表示这段css代码只在该组件上有效,如果不加,那么会应用到整个项目。<style></style>还可以结合css预编译一起使用,比如使用sass处理可以写为:<style lang="sass"></style>
安装依赖
使用.vue文件需要先安装vue-loader、vue-style-loader等加载器并做配置,因为要使用ES6语法,还需要安装babel和babel-loader等加载器,使用npm进行逐个安装:
npm install --save vue
npm install --save-dev vue-loader
npm install --save-dev vue-style-loader
npm install --save-dev vue-template-compiler
npm install --save-dev vue-hot-reload-api
npm install --save-dev babel
npm install --save-dev babel-loader
npm install --save-dev babel-core
npm install --save-dev babel-plugin-transform-runtime
npm install --save-dev babel-preset-2015
npm install --save-dev babel-runtime
安装完成后,修改webpack.config.js来来支持.vue文件及ES6的解析:
//部分代码省略
var config = {
entry: {
main: './index'
},
output: {
path: path.join(__dirname, './dist'),
publicPath: '/dist/',
filename: 'index.js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
css: ExtractTextPlugin.extract({
use: 'css-loader',
fallback: 'vue-style-loader'
})
}
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: 'css-loader',
fallback: 'style-loader'
})
}
]
},
plugins: [
new ExtractTextPlugin('index.css')
]
};
vue-loader在编译.vue文件时,会对<template>、<script>、<style>分别处理,所以在vue-loader选项中多一项options来进一步对不同的语言进行配置,比如对css进行处理时,会先通过"css-loader"解析,然后把处理结果再交给"vue-style-loader"处理。当技术栈多样化时,可以对<template>、<script>、<style>指定不同的语言,比如<template lang="pug"></template>、<script type="text/typescript"></script>、<style lang="sass"></stype>,然后配置loaders就可以了。
配置babel信息
在根目录下新建名称为.babelrc的文件,并写入babel配置,webpack会依赖此文件配置来使用babel编译ES6,代码如下:
{
"presets": [
"ES2015"
],
"plugins": [
"transform-runtime"
],
"comments": false
}
编写app.vue
代码如下:
<template>
<div>
{{message}}
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
message: 'This app.vue'
};
},
}
</script>
<style scoped>
div {
color: goldenrod;
font-size: 18px;
}
</style>
在<template>内写的HTML写法通html文件完全一样,不需要加"\ "换行,webpack最终会把它变异成Render函数的形式。写在<style>里的样式,已经用插件extract-text-webpak-plugin配置过了,最终会统一提取并打包到index.css里,因为加了scoped属性,这部分样式只针对app.vue组件有效。
修改入口js文件
.vue的组件是没有名称的,在父组件使用时可以对它进行定义。写好了app.vue组件,就可以在入口文件index.js内使用。index.js代码如下:
// 引入vue
import Vue from 'vue';
// 引入app.vue
import App from './app.vue'
// 创建vue根实例
new Vue({
el: '#app',
render: h => h(App)
})
注意:render: h => h(App)是ES6一种简写方式,可以使用以下方式代替:
new Vue({
el: '#app',
render: (h) => {
return h(App);
}
})
或者
new Vue({
el: '#app',
render: function(h) {
return h(App);
}
})
修改index.html
在index.js中,把初始化Vue对象时挂在一个id="app"的元素上,那么需要修改index.html文件,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="dist/index.css">
</head>
<body>
<div id="app"></div>
<script src="dist/index.js"></script>
</body>
</html>
运行
执行命令:npm run dev,这个vue工程就跑起来了,效果如下:
在控制台我们可以看到,id="app"的内容被
<div data-v-65bf5ec8="">This app.vue</div>
代替,而且在index.css样式表中对应有
div[data-v-65bf5ec8] {
color: goldenrod;
font-size: 18px;
}
之所以有这段代码,就是因为在app.vue中的<style>中加了scoped属性。
附加代码
在根目录下新建一个components文件夹,新建title.vue和count.vue,并在app.vue中引用这两个组件,具体代码如下:
- //title.vue,代码如下:
<template>
<nav>
<ul class="nav">
<li
v-for="(item, idx) in navs"
:key="idx"
:value="item.value"
:class="{'active': idx === 0}"
>
<a href="javascript:void(0);">{{item.text}}</a>
</li>
</ul>
</nav>
</template>
<script>
export default {
data() {
return {
navs: [
{
text: '新闻',
vaule: 'news'
},
{
text: '视频',
vaule: 'videos'
},
{
text: '生活',
vaule: 'life'
}
]
};
},
}
</script>
<style scoped>
ul {
list-style-type: none;
}
ul:after {
content: "";
display: table;
clear: both;
}
ul li {
float: left;
padding: 10px 15px;
font-size: 16px;
}
ul li a {
text-decoration: none;
color: #333;
}
ul li.active {
border-bottom: 2px solid #299cee;
}
</style>
- count.vue(v-model语法糖示例),代码如下:
<template>
<div class="count">
<button @click="handleDecrement">-</button>
{{currentValue}}
<button @click="handleIncrement">+</button>
</div>
</template>
<script>
export default {
data() {
return {
currentValue: this.value
};
},
props: {
value: {
type: Number,
default: 0
}
},
watch: {
currentValue(newValue) {
this.$emit('input', newValue);
}
},
methods: {
handleDecrement() {
this.currentValue--;
},
handleIncrement() {
this.currentValue++;
}
}
}
</script>
<style scoped>
.count {
color: #999;
}
.count button {
padding: 0 10px;
text-align: center;
line-height: 24px;
}
</style>
- app.vue,代码如下:
<template>
<div>
<vTitle></vTitle>
<vCount v-model="count"></vCount>
<p>app.vue count {{count}}</p>
</div>
</template>
<script>
import vTitle from './components/title.vue';
import vCount from './components/count.vue';
export default {
name: 'app',
components: {
vTitle,
vCount
},
data() {
return {
count: 10
};
}
}
</script>
<style scoped>
div {
color: goldenrod;
font-size: 18px;
}
</style>
运行工程,即可出现如下效果:
app.gif
至此我们完成了一个最基本的vue工程。
完整代码github地址:https://github.com/zhiyuanMain/zhihu-daily
网友评论