截止上一節(jié),我們學習了webpack的四大核心思想:入口(entry)智什、出口(output)动漾、加載器(loaders)、插件(plugins)荠锭,并且初步創(chuàng)建了一個可以在本地端口運行的工程谦炬。接下來我們繼續(xù)探討學習.vue單文件組件的使用和編譯。
眾所周知节沦,Vue.js官網(wǎng)提供了組件的三種使用方法:
字符串 (例如:template: '...')
<script type="text/x-template">
單文件組件 (.vue)
- 第一種方法使用起來需要在js內(nèi)拼接DOM字符串键思,尤其是用" \ "換行的時候。
- 第二種方法可以用于模板特別大的 demo 或極小型的應(yīng)用甫贯,但是其它情況下請避免使用吼鳞,因為這會將模板和該組件的其它定義分離開。這個方法也可以
異步調(diào)用
叫搁。 - 本篇著重介紹第三種方法赔桌,它是構(gòu)建SPA常用的形式。
.vue文件的構(gòu)成
一個.vue文件包括三部分渴逻,<templtae>疾党、<script>、<style>惨奕,可以沒有<style>雪位,在根目錄下創(chuàng)建app.vue文件,快速建立vue預(yù)制模板
梨撞,如下:
下面解讀一下各部分代表的意義:
- <template></template>之間的代碼就是該組件的模板html雹洗,和正常書寫html一樣,不需要引號和換行符卧波。
- <script></script>大家都很熟悉时肿,書寫js代碼,.vue文件通常使用ES6處理該組件的業(yè)務(wù)邏輯港粱。
- <style></style>之間是css代碼螃成,示例中的<style>標簽使用了scoped屬性,表示這段css代碼只在該組件上有效查坪,如果不加寸宏,那么會應(yīng)用到整個項目。<style></style>還可以結(jié)合css預(yù)編譯一起使用咪惠,比如使用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"解析,然后把處理結(jié)果再交給"vue-style-loader"處理落午。當技術(shù)棧多樣化時谎懦,可以對<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>內(nèi)寫的HTML寫法通html文件完全一樣走哺,不需要加"\ "換行蚯嫌,webpack最終會把它變異成Render函數(shù)的形式。寫在<style>里的樣式割坠,已經(jīng)用插件extract-text-webpak-plugin配置過了齐帚,最終會統(tǒng)一提取并打包到index.css里妒牙,因為加了scoped屬性彼哼,這部分樣式只針對app.vue組件有效。
修改入口js文件
.vue的組件是沒有名稱的湘今,在父組件使用時可以對它進行定義敢朱。寫好了app.vue組件,就可以在入口文件index.js內(nèi)使用摩瞎。index.js代碼如下:
// 引入vue
import Vue from 'vue';
// 引入app.vue
import App from './app.vue'
// 創(chuàng)建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>
運行
執(zhí)行命令:npm run dev,這個vue工程就跑起來了上渴,效果如下:
在控制臺我們可以看到岸梨,id="app"的內(nèi)容被
<div data-v-65bf5ec8="">This app.vue</div>
代替喜颁,而且在index.css樣式表中對應(yīng)有
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>
運行工程纠永,即可出現(xiàn)如下效果:
至此我們完成了一個最基本的vue工程。
完整代碼github地址:https://github.com/zhiyuanMain/zhihu-daily