- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) > web開(kāi)發(fā) > JavaScript >
- vue單文件組件的實(shí)現
最近翻閱了一下vue。發(fā)覺(jué)有一個(gè)單文件組件之前基本忽視掉了。vue.js中的單文件組件允許在一個(gè)文件中定義一個(gè)組件的所有內容。也就是說(shuō),一個(gè)頁(yè)面或者是一個(gè)組件,我們想將他們捆綁在一起,那么vue的這個(gè)單文件組件可以做到。正如vue的官網(wǎng)說(shuō)的,“在很多 Vue 項目中,我們使用 app.component 來(lái)定義全局組件,緊接著(zhù)用 app.mount('#app') 在每個(gè)頁(yè)面內指定一個(gè)容器元素?!边@里的組件,都是相對簡(jiǎn)單的,而面對一個(gè)比較復雜的項目,這種方式就行不通。原因如下:
所有這些都可以通過(guò)擴展名為 .vue 的 single-file components (單文件組件) 來(lái)解決,并且還可以使用 webpack 或 Browserify 等構建工具。
那么vue項目中的單文件組件需要如何創(chuàng )建呢?
npm install -D @vue/compiler-sfc
在控制臺上輸入上述的代碼,然后就會(huì )出現一個(gè)文件夾和另一個(gè)json文件。如下:
我們要構建單文件組件,就要自個(gè)制定文件。同時(shí)對webpack也要有一定的了解才行。
比如說(shuō),我們自己安裝一些需要的依賴(lài)。比如說(shuō),css-loader、css的預編譯處理器等等。因為需要項目對vue文件進(jìn)行解析,那么vue-loader是必須的。
這些文件其實(shí)都是vue的簡(jiǎn)單版本。比如簡(jiǎn)單版的hello.vue文件,可以如下
由此可以看見(jiàn): 三個(gè)部分組成。而template這個(gè)部分是不可缺少的,其它的兩個(gè)部分,style和script還可以忽略掉。
script讓你的頁(yè)面js可以跟vue完美結合,而style可以使用預處理器來(lái)構建簡(jiǎn)潔和功能更豐富的組件。(這個(gè)單文件組件很像最初前端開(kāi)發(fā)中的html文檔,它有自己的style標簽和script標簽,只是表現層使用一個(gè)template標簽。由于使用了簡(jiǎn)單的方式,得到一個(gè)強大的分層組件(內容/模板:,表現:
可能有的小伙伴喜歡將不同模塊拆分開(kāi)來(lái),也就是vue文檔說(shuō)的關(guān)注點(diǎn)分離。那么沒(méi)有關(guān)系,你可以拆開(kāi)那些文檔,將css和js拆開(kāi)到另一個(gè)文件,之后引入進(jìn)組件中。如下:
<!-- my-component.vue --> <template> <div>This will be pre-compiled</div> </template> <script src="./my-component.js"></script> <style src="./my-component.css"></style>
項目大致目錄如下:
其中,index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Vue Simple Todo App with SFC</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css" rel="external nofollow" rel="external nofollow" /> <link rel="stylesheet" href="/dist/main.css" rel="external nofollow" rel="external nofollow" /> </head> <body> <div id="app"></div> <script src="/dist/main.js"></script> </body> </html>
package.json
{ "private": true, "scripts": { "dev": "webpack-dev-server", "build": "webpack --env.prod" }, "dependencies": { "vue": "^3.1.1" }, "devDependencies": { "@vue/compiler-sfc": "^3.1.1", "css-loader": "^3.5.2", "file-loader": "^6.0.0", "mini-css-extract-plugin": "^0.9.0", "stylus": "^0.54.7", "stylus-loader": "^3.0.2", "url-loader": "^4.1.0", "vue-loader": "^16.0.0-alpha.3", "vue-style-loader": "^4.1.2", "webpack": "^4.42.1", "webpack-cli": "^3.3.11", "webpack-dev-server": "^3.10.3" }, "keywords": ["todo", "vue"], "name": "vue-todo-list-app-with-single-file-component", "description": "A simple todo list application written in Vue with Single File Component (SFC) support." }
webpack.config.js
const path = require("path"); const { VueLoaderPlugin } = require("vue-loader"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = (env = {}) => ({ mode: env.prod ? "production" : "development", devtool: env.prod ? "source-map" : "cheap-module-eval-source-map", entry: [ env.prod ? false : require.resolve(`webpack-dev-server/client`), path.resolve(__dirname, "./src/main.js") ].filter(Boolean), output: { path: path.resolve(__dirname, "./dist"), publicPath: "/dist/" }, resolve: { alias: { // this isn't technically needed, since the default `vue` entry for bundlers // is a simple `export * from '@vue/runtime-dom`. However having this // extra re-export somehow causes webpack to always invalidate the module // on the first HMR update and causes the page to reload. vue: "@vue/runtime-dom" } }, module: { rules: [ { test: /\.vue$/, use: "vue-loader" }, { test: /\.png$/, use: { loader: "url-loader", options: { limit: 8192 } } }, { test: /\.css$/, use: [ { loader: MiniCssExtractPlugin.loader, options: { hmr: !env.prod } }, "css-loader" ] }, { test: /\.stylus$/, use: ["vue-style-loader", "css-loader", "stylus-loader"] }, { test: /\.pug$/, loader: "pug-plain-loader" } ] }, plugins: [ new VueLoaderPlugin(), new MiniCssExtractPlugin({ filename: "[name].css" }) ], devServer: { inline: true, hot: true, stats: "minimal", contentBase: __dirname, overlay: true, injectClient: false, disableHostCheck: true } });
test.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Vue Simple Todo App with SFC</title> <link rel="stylesheet" rel="external nofollow" rel="external nofollow" /> <link rel="stylesheet" href="/dist/main.css" rel="external nofollow" rel="external nofollow" /> </head> <body> <div id="app222">test pages</div> <script src="/dist/main.js"></script> </body> </html>
src文件夾里邊有三個(gè)文件,App.vue main.js 和TodoItem.vue
其中:App.vue
<template> <div class="wrapper"> <h1>My Todo List</h1> <form @submit.prevent="addTodo"> <input type="text" name="todo-text" v-model="newTodoText" placeholder="New todo"> </form> <ul v-if="todos.length"> <TodoItem v-for="todo in todos" :key="todo.id" :todo="todo" @remove="removeTodo"/> </ul> <p class="none" v-else>Nothing left in the list. Add a new todo in the input above.</p> </div> </template> <script> import TodoItem from "./TodoItem.vue" let nextTodoId = 1 const createTodo = text => ({ text, id: nextTodoId++ }) export default { components: { TodoItem }, data() { return { todos: [ createTodo("Learn Vue"), createTodo("Learn about single-file components"), createTodo("Fall in love ❤️") ], newTodoText: "" } }, methods: { addTodo() { const trimmedText = this.newTodoText.trim() if (trimmedText) { this.todos.push(createTodo(trimmedText)) } this.newTodoText = "" }, removeTodo(item) { this.todos = this.todos.filter(todo => todo !== item) } } } </script> <style lang="stylus"> *, *::before, *::after box-sizing border-box html, body font 16px/1.2 BlinkMacSystemFont, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif padding 10px .wrapper width 75% margin 0 auto form margin-bottom 20px input[type="text"] width 100% padding 10px border 1px solid #777 ul, li margin 0 padding 0 p.none color #888 font-size small </style>
main.js
import { createApp } from 'vue' import App from './App.vue' createApp(App).mount('#app')
TodoItem.vue
<template> <li> <span>{{ todo.text }}</span> <button @click.prevent="$emit('remove', todo)">Remove</button> </li> </template> <script> export default { props: { todo: { required: true, type: Object } } } </script> <style lang="stylus" scoped> li display flex margin 5px 0 span flex 1 button border 1px solid orange background orange color white font-size 0.8rem padding 2px 4px cursor pointer &:hover border-color #ff8100 background #ff8100 </style>
注意
如果不懂得webpack,建議還是按照官網(wǎng)的指示,用vue的腳手架安裝基本的工具。
或者是按照我給的pakage.json放到項目上,npm install一下,安裝好最基本的環(huán)境,然后可以通過(guò)npm run dev進(jìn)行本地開(kāi)發(fā)。
其實(shí),我覺(jué)得這個(gè)單文件組件用處已經(jīng)比較小。除非就是一個(gè)純js的項目,用的庫和組件都已經(jīng)非常的古老,那么這個(gè)時(shí)候用這個(gè)單文件組件來(lái)進(jìn)行新的功能開(kāi)發(fā),效果還是不錯的,前提是你要對vue比較熟悉。同時(shí),我建議還是要學(xué)習一下webpack。不要對bable都一竅不通,然后還要通過(guò)node去啟動(dòng)項目。
其實(shí),用一個(gè)文件就將html/css/JavaScript分層管理,統一到了一個(gè)文件,著(zhù)實(shí)能夠讓我們的項目看起來(lái)更加的有條理,規范性更加好。因為我們的jq時(shí)代,常常會(huì )將css混雜在html中,而且,簡(jiǎn)單的一個(gè)點(diǎn)擊事件都要將它們分割開(kāi),這體驗當然沒(méi)有“分層而治”那么分明。
參考文獻:
1、
2、
到此這篇關(guān)于vue單文件組件的實(shí)現的文章就介紹到這了,更多相關(guān)vue單文件組件內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。
Copyright ? 2009-2022 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 特網(wǎng)科技 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 百度云 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站