npm init -y
對文件夾進行初始化,完成後多了個package.json文件。npm install vue --save
命令安裝Vue。安裝完後多了一個文件夾node_modules和package-lock.json,node_modules是NPM安裝的模塊的默認存放位置,打開發現其中有個Vue文件夾。javascript
先看一個例子php
<!DOCTYPE html> <html> <head> <!-- 注意路徑--> <script src="../node_modules/vue/dist/vue.js"></script> </head> <body> <div id="app"> 數量爲:<input type="text" v-model="num"><br> <button v-on:click="increase">點我+1</button> </div> <script type="text/javascript"> var app = new Vue({ el: "#app", data: { num: 1 }, methods: { increase: function() { this.num++; } } }) </script> </body> </html>
效果: 設置文本框中的數字,點擊+1後在原來的基礎上增長1。css
建立方式以下,html
el表示要關聯的HTML模版的id,前端
data表示模版中數據的初始值,vue
methods定義了模板中出現的函數。java
var app = new Vue({ el: "#app", data: {num: 1}, methods: { increase: function() { this.num++; } } })
注意:這段代碼必須寫在html模版下面,不然不生效。node
要渲染的html模版,其id爲app
對應於Vue構造函數中el的值#app
。webpack
Vue只能渲染這個div內部的變量,方法等元素。ios
<div id="app"> 數量爲:<input type="text" v-model="num"><br> <button v-on:click="increase">點我+1</button> </div>
這是Vue的特性:雙向綁定。
上面的例子中,點擊+1按鈕,觸發increase方法,Vue實例中的num+1,文本框中顯示的數字+1;
改變文本框中的數字,再點+1按鈕,數字就會在原來基礎上+1,說明修改顯示內容也能修改對應的Vue實例中的變量。
這就是視圖和數據的雙向綁定,修改視圖,數據就變;修改數據,視圖也變。
按鈕經過v-on:click指令綁定了increase方法,方法的定義在Vue對象的methods屬性裏面。
html
<button v-on:click="increase">點我+1</button>
js
var app = new Vue({ ... methods: { increase: function() { this.num++; } } })
每一個Vue實例在被建立時都要通過一系列的初始化過程,好比建立實例,裝載模板等等。Vue爲生命週期的每一個狀態都設置了監聽函數。此處應該有個圖片,但這個圖片太長了,給個地址本身看去吧
使用方式以下
var vm = new Vue({ el:"#app", data:{...}, //監聽函數 created(){ ... } })
像jsp中的EL表達式同樣,顯示變量或者一個表達式的結果,有{{}}
、v-text
、v-html
三種指令
v-html
指令輸出html文本後會自動渲染。
代碼
<div id="test1"> 「花括號表達式的值:」{{1+1}}<br> 「v-text」標籤輸出表達式的值:<span v-text="1+1"></span> <br> 「v-html」標籤輸出表達式的值:<span v-html="1+1"></span> <br> 「花括號輸出文本內容:」{{hello}}<br> 「v-text」標籤輸出普通文本:<span v-text="hello"></span> <br> 「v-html」標籤渲染html文本:<span v-html="hello"></span> </div> <script type="text/javascript"> var app = new Vue({ el: "#test1", data: { hello: "<h1>你們好,我是小明</h1>" } }) </script>
結果
插值表達式只能經過改變變量來改變顯示的內容,而v-model
指令可讓數據和視圖相互影響。
因爲視圖可操做,所以限制了對應的html標籤的種類。v-model
指令支持的標籤有
代碼
<div id="test2"> <input type="checkbox" v-model="language" value="Java" />Java<br /> <input type="checkbox" v-model="language" value="PHP" />PHP<br /> <input type="checkbox" v-model="language" value="Swift" />Swift<br /> <h1> 你選擇了:{{language.join(',')}} </h1> </div> <script type="text/javascript"> var vm = new Vue({ el: "#test2", data: { language: [] } }) </script>
結果
選擇複選框後顯示的內容會對應變化;後臺修改數據,顯示的選擇項也會變化。
爲元素綁定事件。好比綁定點擊事件的語法是v-on:click
,能夠簡寫爲@click
。
<!-- 給頁面元素綁定事件 --> <div id="test3"> <!--事件中直接寫js片斷--> <button v-on:click="num++">增長</button><br /> <!--事件指定一個回調函數,必須是Vue實例中定義的函數--> <button v-on:click="decrement">減小</button><br /> <!-- 簡寫方式 --> <button @click="decrement">減小</button><br /> <!--鍵盤事件--> <button @keyup.enter="num++">先使我得到焦點,而後按下enter鍵增長</button><br /> <h1>num: {{num}}</h1> </div> <script type="text/javascript"> var app = new Vue({ el: "#test3", data: { num: 1 }, methods: { decrement() { this.num--; } } }) </script>
用於循環遍歷數據
遍歷數組
<!-- 遍歷數組 --> <div id="test4"> <ul> <li v-for="(user,index) in users"> {{index}} - {{user.name}} : {{user.gender}} : {{user.age}} </li> </ul> </div> <script type="text/javascript"> var vm = new Vue({ el: "#test4", data: { users: [{ name: '小紅', gender: '女', age: 11 }, { name: '小明', gender: '男', age: 10 } ] } }) </script>
遍歷對象
<div id="test5"> <ul> <li v-for="(value,key,index) in user"> {{index}} - {{key}} : {{value}} </li> </ul> </div> <script type="text/javascript"> var vm = new Vue({ el: "#test5", data: { user: { name: '小明', gender: '男', age: 10 } } }) </script>
v-if用於條件判斷
<div id="test6"> <!--事件中直接寫js片斷--> <button v-on:click="show = !show">點擊切換</button><br /> <h1 v-if="show"> 你好 </h1> </div> <script type="text/javascript"> var app = new Vue({ el: "#test6", data: { show: true } }) </script>
點擊按鈕,文本內容會隱藏。
v-if也能夠和v-for結合使用
<div id="test7"> <ul> <li v-for="(user,index) in users" v-if="user.gender === '女'"> {{index}} - {{user.name}} : {{user.gender}} : {{user.age}} </li> </ul> </div> <script type="text/javascript"> var vm = new Vue({ el: "#test7", data: { users: [{ name: '小紅', gender: '女', age: 10 }, { name: '小明', gender: '男', age: 10 } ] } }) </script>
結果只顯示一個小紅
有if固然也有else和elseif
<div v-if="type === 'A'"> A </div> <div v-else-if="type === 'B'"> B </div> <div v-else-if="type === 'C'"> C </div> <div v-else> Not A/B/C </div>
v-show控制元素的顯示,若是元素隱藏了,並非從dom中移除,而是設置display爲none
<div id="test6"> <!--事件中直接寫js片斷--> <button v-on:click="show = !show">點擊切換</button><br /> <h1 v-show="show"> 你好 </h1> </div> <script type="text/javascript"> var app = new Vue({ el: "#test6", data: { show: true } }) </script>
假如咱們想改變class屬性,這樣寫是錯誤的
<div class="{{isAcctive}}"></div>
由於插值表達式不能用於屬性的值中。
咱們能夠藉助v-bind:class
指令,能夠簡寫爲:class
<div id="test8"> <div :class="isActive">注意class的值</div> </div> <script type="text/javascript"> var app = new Vue({ el: "#test8", data: { isActive: ['active', 'hasError'] } }) </script>
結果
在插值表達式中寫一長串代碼很難看,能夠用「計算屬性」來替代,這個屬性其實是個方法,將方法名以變量形式綁定到插值表達式中了:
<div id="test9"> <h1>您的生日是:{{birth}} </h1> </div> <script type="text/javascript"> var app = new Vue({ el: "#test9", data: { birthday: 1429032123201 // 毫秒值 }, computed: { birth() { // 計算屬性本質是一個方法,可是必須返回結果 const d = new Date(this.birthday); return d.getFullYear() + "-" + d.getMonth() + "-" + d.getDay(); } } }) </script>
結果
假如咱們要監控用戶輸入了什麼內容,能夠用監控屬性來實現
<!-- 監控屬性變化 --> <div id="test10"> <input type="text" v-model="message"> </div> <script type="text/javascript"> var vm = new Vue({ el: "#test10", data: { message: "" }, watch: { message(newVal, oldVal) { console.log(newVal, oldVal); } } }) </script>
結果
在文本框輸入good,控制檯記錄了每一個按鍵按下的動做
一個頁面中總有相同的部分能夠抽取出來作爲組件使用,Vue提供了定義組件的方法。
代碼
<div id="test1"> <counter></counter> </div> <script type="text/javascript"> // 定義全局組件,參數1,組件名稱;參數2,組件參數。 // 用html模板替換掉了counter標籤,注意數據傳遞的方式,是data()而不是data Vue.component("counter", { template: '<button v-on:click="count++">你點了我 {{ count }} 次</button>', data() { return { count: 0 } } }) var app = new Vue({ el: "#test1" }); </script>
頁面表現
定義全局組件後,能夠在其餘地方使用。
值得注意的一點:使用者必須也是一個Vue實例。
<div id="test2"> <counter></counter> <counter></counter> <counter></counter> </div> <script type="text/javascript"> var app = new Vue({ el: "#test2" }); </script>
現象
能夠看出:每一個組件都維護本身的一份變量。
就像定義變量同樣定義了一個局部組件localCounter
,將其註冊到咱們自定義的<test-component></test-component>
標籤中。
注意:此處用了駝峯命名法來對應標籤:testComponent對應於test-component
<div id="test3"> <test-component></test-component> </div> <script type="text/javascript"> const localCounter = { template: '<button v-on:click="count++">我是局部組件:你點了我 {{ count }} 次</button>', data() { return { count: 0 } } }; var app = new Vue({ el: "#test3", components: { testComponent: localCounter } }); </script>
下面的例子展現了:父組件獲得lessons的數據後傳遞到子組件中,以子組件的模板顯示
<div id="test4"> <parent :items="lessons" /> </div> <script type="text/javascript"> //子組件,經過props來接收父組件傳過來的數據 //這個子組件是一個局部組件 const son = { template: '<ul>\ <li v-for="item in items" :key="item.id">{{item.id}} : {{item.name}}</li>\ </ul>', props: { items: { type: Array, default: [] } } } var app = new Vue({ el: "#test4", components: { parent: son }, data: { lessons: [ {id: 1,name: 'java'}, {id: 2,name: 'php'}, {id: 3,name: 'ios'}, ] } }) </script>
現象
代碼
<div id="test5"> <h2>num: {{num}}</h2> <my-component @inc="increment" @dec="decrement"></my-component> </div> <script type="text/javascript"> Vue.component("myComponent", { template: '\ <div>\ <button @click="plus">加</button> \ <button @click="reduce">減</button> \ </div>', methods: { plus() { this.$emit("inc"); }, reduce() { this.$emit("dec"); } } }) var app = new Vue({ el: "#test5", data: { num: 0 }, methods: { increment() { this.num++; }, decrement() { this.num--; } } }); </script>
現象
點擊加按鈕,數值增長;點擊減按鈕,數量減小。
解釋
父組件是
<my-component @inc="increment" @dec="decrement"></my-component>
子組件是
Vue.component("myComponent", { template: '\ <div>\ <button @click="plus">加</button> \ <button @click="reduce">減</button> \ </div>', methods: { plus() { this.$emit("inc"); }, reduce() { this.$emit("dec"); } } })
想要經過子組件中的加和減按鈕實現num的加和減,就要調用父組件的函數。
$emit()
方法是Vue提供的用於調取父組件綁定函數的函數。
最後流程就是:點擊加按鈕,調用子組件的plus方法,plus方法調取父組件的increment方法實現num的增長操做。
安裝命令npm install vue-router --save
引入依賴
<script src="../node_modules/vue-router/dist/vue-router.js"></script>
利用vue-router實現登陸註冊菜單的切換:
點擊登陸後顯示登陸頁
點擊註冊後顯示註冊頁
將登陸、註冊和路由分紅三個組件,由index.html引入並使用。目錄結構以下
login.js
const loginForm = { template:'\ <div>\ <h2>登陸頁</h2> \ 用戶名:<input type="text"><br/>\ 密碼:<input type="password"><br/>\ </div>\ ' }
register.js
const registerForm = { template:'\ <div>\ <h2>註冊頁</h2> \ 用戶名:<input type="text"><br/>\ 密碼:<input type="password"><br/>\ 確認密碼:<input type="password"><br/>\ </div>\ ' }
router.js
// 根據路徑渲染對應的組件 const indexRouter = new VueRouter({ routes:[ { path:"/login", component: loginForm }, { path: "/register", component: registerForm } ] })
index.html
<!DOCTYPE html> <html> <head> <script src="../node_modules/vue/dist/vue.js"></script> <script src="../node_modules/vue-router/dist/vue-router.js"></script> </head> <body> <div id="app"> <!-- 跳轉連接,點擊後將地址傳送給router --> <span><router-link to="/login">登陸</router-link></span> <span><router-link to="/register">註冊</router-link></span> <hr/> <div> <!-- 路由錨點,點擊跳轉連接後router會在此渲染對應組件的html模板--> <router-view></router-view> </div> </div> <script src="js/login.js"></script> <script src="js/register.js"></script> <script src="js/router.js"></script> <script type="text/javascript"> var vm = new Vue({ el: "#app", router: indexRouter //使用路由 }) </script> </body> </html>
Webpack 是一個前端資源的打包工具,它能夠將js、image、css等資源打包成一個總體,壓縮混淆提升性能和安全性,將高級語法轉義,提升兼容性。
入口(entry)
webpack打包的啓點,能夠有一個或多個,通常是js文件。webpack會從啓點文件開始,尋找啓點直接或間接依賴的其它全部的依賴,包括JS、CSS、圖片資源等,做爲未來打包的原始數據。
輸出(output)
出口通常包含兩個屬性:path和filename。用來告訴webpack打包的目標文件夾,以及文件的名稱。目的地也能夠有多個。
加載器(loader)
webpack自己只識別Js文件,若是要加載非JS文件,必須指定一些額外的加載器(loader),例如css-loader。而後將這些文件轉爲webpack能處理的有效模塊,最後利用webpack的打包能力去處理。
插件(plugins)
插件能夠擴展webpack的功能,讓webpack不只僅是完成打包,甚至各類更復雜的功能,或者是對打包功能進行優化、壓縮,提升效率。
執行命令npm install webpack webpack-cli --save-dev
在package.json裏多了幾行配置,分別是運行時依賴和開發依賴
先在package.json同級的目錄下新建webpack.config.js文件。
接下來以vue-router的demo爲例演示webpack的用法。
入口通常是一個或多個js文件,經過這些js文件找出相關的全部依賴樹,最後打包輸出。
在vue-router的demo裏面,index.html引用了相關的js,但它是html文件,不適合做爲啓點。
所以咱們須要一個額外的main.js引入其餘全部的js。
main.js
//ES6語法導入js模塊,注意:不帶.js後綴 import Vue from '../node_modules/vue/dist/vue' import VueRouter from '../node_modules/vue-router/dist/vue-router' import loginForm from './js/login' import registerForm from './js/register' //VueRouter使用模塊加載,必須加上這一句 Vue.use(VueRouter) const indexRouter = new VueRouter({ routes:[ { path:"/login", component: loginForm }, { path: "/register", component: registerForm } ] }) var vm = new Vue({ el: "#app", router: indexRouter })
loginForm和registerForm都是作爲js模塊導入的,他們本身也要分別追加導出語句。
在login.js中追加一句
export default loginForm;
在register.js中追加一句
export default registerForm;
最後配置入口:在webpack.config.js中指定入口文件
module.exports={ entry:'./src/main.js', //指定打包的入口文件 }
在webpack.config.js中指定出口路徑和最終輸出的文件名,最終的js以下
module.exports={ entry:'./src/main.js', //指定打包的入口文件 output:{ // path: 輸出的目錄,__dirname是相對於webpack.config.js配置文件的絕對路徑 path : __dirname+'/dist', filename:'build.js' //輸出的js文件名 } }
執行命令npx webpack --config webpack.config.js
去掉index.html中的js引用標籤,只引用打包好的build.js
<script src="../dist/build.js"></script>
測試運行,結果與打包以前同樣。
webpack的四個核心概念,咱們目前只使用了兩個:入口和出口。
接下來使用加載器,加載非js資源,好比CSS。
執行命令:npm install style-loader css-loader --save-dev
新建一個和js目錄同級的css文件夾,裏面新建main.css
#app a{ display: inline-block; width: 150px; line-height: 30px; background-color: dodgerblue; color: white; font-size: 16px; text-decoration: none; } #app a:hover{ background-color: whitesmoke; color: dodgerblue; } #app div{ width: 300px; height: 150px; } #app{ width: 400px; border: 1px solid dodgerblue; }
在main.js中添加import語句
import './css/main.css'
在webpack.config.js裏配置,最終以下所示
module.exports={ entry:'./src/main.js', //指定打包的入口文件 output:{ // path: 輸出的目錄,__dirname是相對於webpack.config.js配置文件的絕對路徑 path : __dirname+'/dist', filename:'build.js' //輸出的js文件名 }, module: { rules: [ { test: /\.css$/, // 經過正則表達式匹配全部以.css後綴的文件 use: [ // 要使用的加載器,這兩個順序必定不要亂 'style-loader', 'css-loader' ] } ] } }
依然是執行npx webpack --config webpack.config.js
最終的CSS效果可以展現出來(不貼圖片了)。
注意:全部的js、css最終都被放到了build.js裏面。
package.json裏面能夠配置腳本,在scripts標籤裏面添加"build": "webpack"
{ "name": "vue-test", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "vue": "^2.6.10", "vue-router": "^3.0.6" }, "devDependencies": { "css-loader": "^2.1.1", "style-loader": "^0.23.1", "webpack": "^4.33.0", "webpack-cli": "^3.3.3" } }
這樣就能夠執行npm run build
命令進行打包,代替原先的npx webpack --config webpack.config.js
命令。
以前都是將js、css等相關文件打包好,最後手動引入到index.html中。
而webpack的html打包插件,能夠把html和js、css等一塊兒打包直接生成可用的頁面。
執行npm install --save-dev html-webpack-plugin
命令安裝
配置webpack.config.js,最終以下
const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports={ entry:'./src/main.js', //指定打包的入口文件 output:{ // path: 輸出的目錄,__dirname是相對於webpack.config.js配置文件的絕對路徑 path : __dirname+'/dist', filename:'build.js' //輸出的js文件名 }, module: { rules: [ { test: /\.css$/, // 經過正則表達式匹配全部以.css後綴的文件 use: [ // 要使用的加載器,這兩個順序必定不要亂 'style-loader', 'css-loader' ] } ] }, plugins:[ new HtmlWebpackPlugin({ title: '首頁', //生成的頁面標題<head><title>首頁</title></head> filename: 'index.html', // dist目錄下生成的文件名 template: './src/index.html' // 咱們原來的index.html,做爲模板 }) ] }
去掉原先index.html裏面的引用build.js的標籤
執行打包命令npm run build
發現dist文件夾下多了個index.html,運行發現效果與以前一致。
每次修改js或css都要從新打包,麻煩,webpack提供了一個熱更新插件,這個插件搞了一個服務器,
咱們修改代碼後,能夠自動檢測修改並更新。
安裝命令是:npm install webpack-dev-server --save-dev
以後在package.json中的scripts標籤下添加
"dev": "webpack-dev-server --inline --hot --open --port 8081 --host 127.0.0.1"
注意端口號。
執行命令npm run dev
,注意:是dev,不是build。
使用webpack打包vue項目時須要咱們手動安裝插件、配置等,很麻煩。Vue提供了一個腳手架,Vue-cli,可以快速搭建一個web項目模板。
執行命令npm install -g vue-cli
初始化webpackvue init webpack
,接下來這樣選擇
項目的入口文件
文件內容以下
<template> <div id="app"> <img src="./assets/logo.png"> <router-view/> </div> </template> <script> export default { name: 'App' } </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>
*.vue文件叫作單文件組件,每個.vue文件都是一個獨立的vue組件。
裏面包含三部份內容
template:模板,支持html語法高亮和提示
script:js腳本,這裏編寫的就是vue的組件對象,看到上面的data(){}了吧
style:樣式,支持CSS語法高亮和提示
每一個組件都有本身獨立的html、JS、CSS,互不干擾,真正作到可獨立複用。
{ "name": "vue-cli-test", "version": "1.0.0", "description": "", "author": "", "private": true, "scripts": { "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", "start": "npm run dev", "build": "node build/build.js" }, "dependencies": { "vue": "^2.5.2", "vue-router": "^3.0.1" }, "devDependencies": { "autoprefixer": "^7.1.2", "babel-core": "^6.22.1", "babel-helper-vue-jsx-merge-props": "^2.0.3", "babel-loader": "^7.1.1", "babel-plugin-syntax-jsx": "^6.18.0", "babel-plugin-transform-runtime": "^6.22.0", "babel-plugin-transform-vue-jsx": "^3.5.0", "babel-preset-env": "^1.3.2", "babel-preset-stage-2": "^6.22.0", "chalk": "^2.0.1", "copy-webpack-plugin": "^4.0.1", "css-loader": "^0.28.0", "extract-text-webpack-plugin": "^3.0.0", "file-loader": "^1.1.4", "friendly-errors-webpack-plugin": "^1.6.1", "html-webpack-plugin": "^2.30.1", "node-notifier": "^5.1.2", "optimize-css-assets-webpack-plugin": "^3.2.0", "ora": "^1.2.0", "portfinder": "^1.0.13", "postcss-import": "^11.0.0", "postcss-loader": "^2.0.8", "postcss-url": "^7.2.1", "rimraf": "^2.6.0", "semver": "^5.3.0", "shelljs": "^0.7.6", "uglifyjs-webpack-plugin": "^1.1.1", "url-loader": "^0.5.8", "vue-loader": "^13.3.0", "vue-style-loader": "^3.0.1", "vue-template-compiler": "^2.5.2", "webpack": "^3.6.0", "webpack-bundle-analyzer": "^2.9.0", "webpack-dev-server": "^2.9.1", "webpack-merge": "^4.1.0" }, "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" }, "browserslist": [ "> 1%", "last 2 versions", "not ie <= 8" ] }
執行npm run dev
或者 npm start
均可以啓動項目。