來(lái)源 |?https://xueyuanjun.com/post/21940Vue Loader 概述
在上篇教程中,我們提到,如果所有的組件代碼都在單個(gè) HTML 文檔或者 JavaScript 文件中編寫(xiě),會(huì)導(dǎo)致代碼的可讀性和可維護(hù)性很差,為此,Vue 框架引入了 Vue Loader,我們可以通過(guò)它實(shí)現(xiàn)單文件 Vue 組件。Vue Loader 是一個(gè) Webpack loader,因此,使用它之前,需要安裝相關(guān)的依賴(lài)包并手動(dòng)配置 Webpack 支持 Vue Loader,以便編譯打包 Vue 組件文件到相應(yīng)的 JavaScript 文件(相關(guān)安裝配置細(xì)節(jié)請(qǐng)參考 Vue Loader 官方文檔)。如果你對(duì) Webpack 不太了解,或者不想要手動(dòng)去安裝配置,可以基于 Vue.js 框架提供的 Vue CLI 直接創(chuàng)建一個(gè) Vue 原型項(xiàng)目。通過(guò) Vue CLI 創(chuàng)建的原型項(xiàng)目會(huì)針對(duì)大多數(shù)常見(jiàn)的開(kāi)發(fā)需求進(jìn)行預(yù)先 Webpack 配置,這對(duì)于我們學(xué)習(xí)或者快速入門(mén)單文件 Vue 組件開(kāi)發(fā)完全夠用了(如果使用 Laravel 框架進(jìn)行全棧開(kāi)發(fā)的話,Laravel Mix 也是一個(gè)封裝了大多數(shù) Webpack 常用配置的依賴(lài)包,所以在 Laravel 項(xiàng)目中單文件 Vue 組件也是開(kāi)箱可用的),下面我們就基于 Vue CLI 來(lái)創(chuàng)建一個(gè)原型項(xiàng)目,并演示單文件 Vue 組件的編寫(xiě)。通過(guò) Vue CLI 初始化原型項(xiàng)目
使用 Vue CLI 之前,先要通過(guò) NPM 或者 Yarn 全局安裝它:然后,在任意目錄下通過(guò)如下命令初始化一個(gè) Vue 原型項(xiàng)目(這里,我們選擇在?vue_learning?目錄下執(zhí)行):此時(shí)會(huì)出現(xiàn)一個(gè) Preset 選項(xiàng)(包含預(yù)定義選項(xiàng)和插件),我們直接回車(chē)選擇默認(rèn)的 Vue 2:安裝完成后,通過(guò)?cd demo-project?進(jìn)入演示項(xiàng)目,然后運(yùn)行?npm run serve?啟動(dòng)這個(gè)項(xiàng)目:這樣,我們就可以在瀏覽器中通過(guò)?http://localhost:8080?訪問(wèn)這個(gè) Vue 項(xiàng)目了:Vue 原型項(xiàng)目目錄結(jié)構(gòu)
我們來(lái)大致看下這個(gè)演示項(xiàng)目的目錄結(jié)構(gòu):該項(xiàng)目的 HTML 入口文件是?public/index.html(關(guān)于該文檔中?<%=%>?語(yǔ)法的說(shuō)明參考 Vue CLI 官方文檔,這里不詳細(xì)展開(kāi)了):<html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <link rel="icon" href="<%= BASE_URL %>favicon.ico"> <title><%= htmlWebpackPlugin.options.title %>title> head> <body> <noscript> <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.strong> noscript> <div id="app">div> body>html>
對(duì)應(yīng)的 JavaScript 入口文件是?src/main.js:import Vue from 'vue'import App from './App.vue'
Vue.config.productionTip = false
new Vue({ render: h => h(App),}).$mount('#app')
可以看到,Vue 全局對(duì)象實(shí)例通過(guò)?$mount?函數(shù)掛載到了 HTML 視圖的?div#app?元素上,其效果和之前通過(guò)?el:'#app'?屬性設(shè)置實(shí)現(xiàn)掛載完全一致。這種掛載方式的好處是可以先定義 Vue 對(duì)象實(shí)例,再掛載到某個(gè) HTML 元素上。注:HTML 文檔中并沒(méi)有顯示引入任何 JavaScript 文件,這一切都是 Vue CLI 底層自動(dòng)完成的,index.html 會(huì)被當(dāng)作模板進(jìn)行處理,相應(yīng)的 CSS、圖標(biāo)、JavaScript 文件資源也會(huì)自動(dòng)注入進(jìn)去。至于為什么使用這種方式掛載,是因?yàn)?Vue 對(duì)象實(shí)例中使用了?render?函數(shù)的緣故,該函數(shù)是之前通過(guò)?template?屬性定義 Vue 組件字符串模板的替代方案,通過(guò)該函數(shù)可以直接基于 JavaScript 構(gòu)建虛擬 DOM,而不再需要將字符串模板進(jìn)行轉(zhuǎn)化,無(wú)論從功能還是性能角度來(lái)說(shuō)都更加強(qiáng)大,這里的?h?是?createElement?函數(shù)的簡(jiǎn)寫(xiě)(關(guān)于 render 函數(shù)的使用我們后面還會(huì)單獨(dú)介紹)。如果在 Vue 對(duì)象實(shí)例中定義了?render?函數(shù),則 Vue 構(gòu)造函數(shù)不會(huì)從?template?選項(xiàng)或通過(guò)?el?選項(xiàng)指定的掛載元素中提取出 HTML 模板編譯渲染函數(shù),所以這里需要通過(guò)?$mount?函數(shù)去手動(dòng)掛載。這里我們傳入了一個(gè)?App.vue?組件到?h?函數(shù)作為整個(gè) Vue 應(yīng)用組件樹(shù)的根組件,然后把其他功能組件注冊(cè)到?App.vue?中,并以此來(lái)完成整個(gè) Vue 組件樹(shù)的渲染:<template> <div id="app"> <img alt="Vue logo" src="./assets/logo.png"> <HelloWorld msg="Welcome to Your Vue.js App"/> div>template>
<script>import HelloWorld from './components/HelloWorld.vue'
export default { name: 'App', components: { HelloWorld }}script>
<style>#app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px;}style>
比如用于顯示演示項(xiàng)目首頁(yè)的?HelloWorld?組件,這里也可以看到,注冊(cè)組件是通過(guò)?components?屬性,之前我們使用的是?Vue.component?函數(shù),二者的區(qū)別是前者是局部注冊(cè)(注冊(cè)到指定父組件),后者是全局注冊(cè)(整個(gè) Vue 全局對(duì)象實(shí)例作用域內(nèi)有效)。這里的?App.vue?或者?HelloWorld.vue?都是單文件 Vue 組件,單文件 Vue 組件以?.vue?后綴結(jié)尾,可以通過(guò)普通組件注冊(cè)的方式注冊(cè)到指定父級(jí)作用域,并且包含以下結(jié)構(gòu):...:用于定義渲染組件的 HTML 字符串模板,和之前定義的 Vue 組件模板一樣,只能包含一個(gè)根 HTML 元素(可以對(duì)應(yīng)到之前定義組件對(duì)象的?template?屬性);
:用于定義 Vue 組件的 JavaScript 代碼,通過(guò)?export default?返回該 Vue 組件的對(duì)象實(shí)例,其中可以包含前面通過(guò)?Vue.component?定義 Vue 組件對(duì)象定義的除?template?屬性外的所有其他屬性和函數(shù),還有一點(diǎn)不同的是這里的 Vue 組件名通過(guò)?name?屬性顯示設(shè)置;
:用于定義當(dāng)前 Vue 組件模板元素的 CSS 樣式(如果 style 標(biāo)簽設(shè)置了?scoped?屬性,則意味著 CSS 樣式只能在當(dāng)前組件被渲染的時(shí)候生效)。
文字看起來(lái)可能有點(diǎn)懵,接下來(lái)我們通過(guò)單文件 Vue 組件來(lái)重構(gòu)上篇教程編寫(xiě)的模態(tài)框組件進(jìn)行演示。