置身世外只爲暗中觀察!!!Hello你們好,我是魔王哪吒!重學鞏固你的Vuejs知識體系,若是有哪些知識點遺漏,還望在評論中說明,讓我能夠及時更新本篇內容知識體系。歡迎點贊收藏!css
首先:new Vue()
,new
一個Vue
的實例,Observe data
數據查看,init Events
綁定事件,created
執行created
方法,判斷是否有el
屬性,若是沒有,vm.$mount(el)
表示處於未掛載狀態,能夠手動調用這個方法來掛載。判斷是否有template
屬性。html
若是有el
屬性,判斷是否有template
屬性。前端
實例化期和加載期
建立期間的生命週期函數:beforeCreate
和 created
,beforeMount
和 mounted
。vue
beforeCreate
在實例初始化後,數據觀測data observer
和event/watcher
事件配置以前被調用。html5
更新期node
運行期間的生命週期函數:beforeUpdate
和 updated
react
created
實例已經建立完成後被調用。linux
實例已完成如下的配置:數據觀測data observer
,屬性和方法的運算,watch/event
事件回調。webpack
掛載階段還沒開始,$el
屬性目前不可見。ios
beforeMount
在掛載開始以前被調用,相關的render
函數首次被調用。mounted
,vm.$el
已經掛載在文檔內,對已有dom
節點的操做能夠在期間進行。beforeUpdate
數據更新時調用,發生在虛擬dmo
從新渲染和打補丁以前。updated
當這個鉤子被調用時,組件dom
已經更新,因此你如今能夠執行依賴於dom
的操做。activated
,deactivated
,beforeDestroy
,destroyed
。實例銷燬以前調用,vue
實例銷燬後調用。
卸載期
銷燬期間的生命週期函數:beforeDestroy
和 destroyed
實例生命週期鉤子
每一個vue實例在被建立時都要通過一系列的初始化過程,須要設置數據監聽,編譯模板,將實例掛載到dom
並在數據變化時更新dom
等,同時在這個過程當中也會運行一些叫作生命週期鉤子的函數。
用於給用戶在不一樣階段添加本身代碼的機會。
beforeCreate
,此時的data
是不可見的
data() { return { a: 1 } }, beforeCreate() { // red console.log(this.a); // 看不見 }
created
實例已經建立完成後被調用,這個時候你看不見你頁面的內容,實例已完成表示:數據觀測data observer
,屬性和方法的運算,watch/event
事件回調。
這個時候掛載階段還沒開始,$el
屬性目前不可見。
export default { data() { return { a: 1 } }, beforeCreate() { console.log(this.a); }, created() { // red console.log(this.a); console.log(this.$el); // 此時data數據裏面的a可見,this.$el不可見 } }
beforeMount
在掛載開始以前被調用,相關的render
函數首次被調用。
export default{ data() { return { a: 1 } }, beforeCreate() { console.log(this.a); // 不可見 }, created() { console.log(this.a); console.log(this.$el); // 不可見 }, beforeMount() { console.log(this.$el); // 不可見 } }
mounted
:
export default { data() { return { a: 1 } }, mounted() { console.log(this.$el); // 此時$el 可見 } }
beforeUpdate
鉤子,dom
更新以前調用:
beforeUpdate() { console.log(this.a); } // document.getElementById("web").innerHTML
updated
鉤子,dom
更新以後調用:
updated() { console.log(this.a); } // document.getElementById("web").innerHTML
activated
和deactivated
(組件)
activated() { console.log("組件使用了"); }, deactivated() { console.log("組件停用了"); Data to Drag},
keep-alive
是vue
的內置組件,能在組件切換過程當中將狀態保留在內存中,防止重複渲染dom
。
<keep-alive>
包裹動態組件時,會緩存不活動的組件實例,而不會銷燬它們。和<transition>
類似,<keep-alive>
是一個抽象組件:它自身不會渲染一個DOM
元素,也不會出如今父組件鏈中。
當組件在<keep-alive>
內被切換,它的activated
和deactivated
這兩個生命週期鉤子函數將會被對應指定。
它的使用是由於咱們不但願組件被從新渲染而影響使用體驗,或者是性能,避免屢次渲染下降性能。緩存下來,維持當前得狀態。
場景:
keep-alive
生命週期:
初次進入時:created > mounted > activated;退出後觸發 deactivated
;再次進入:會觸發activated
;事件掛載的方法等,只執行一次的放在mounted
中;組件每次進去執行的方法放在 activated
中。
app.vue
父組件:
<template> <div> <button @click="myBtn"> myBtn </button> <keep-alive> <range v-if="isShow"></range> </keep-alive> </div> </template> <script> import range from './components/range.vue' export default { data() { return { a: 1, isShow: true } }, methods: { myBtn() { this.isShow = !this.isShow } }, components: { range } } </script>
beforeDestroy
和destroyed
beeforeDestroy
類型爲function
,詳細:實例銷燬以前調用,在這一步,實例仍然徹底可用。
該鉤子在服務器端渲染期間不被調用。
destroyed
類型爲function
,詳細:vue
實例銷燬後調用,調用後,vue
實例指示的全部東西都會解綁定,全部的事件監聽器會被移除,全部的子實例也會被銷燬。
該鉤子在服務器端渲染期間不被調用。
beforeRouteEnter
和beforeRouteLeave
beforeRouteEnter() { console.log('beforeRouteEnter') }, beforeRouteLeave() { console.log('beforeRouteLeave') }
vue路由使用的,路由進去和路由離開的時候添加的。
created() { console.log('開始執行created鉤子函數') // 獲取data數據 console.log('獲取created屬性'+this.value) // 獲取頁面元素 console.log(this.$refs['example']) this.$nextTick(()=>{ console.log('執行created建立的this.$nextTick()函數') }) }, mounted() { console.log('開始執行mounted鉤子函數') // 獲取掛載數據 console.log('獲取掛載數據--'+this.$refs['example'].innerText) this.$nextTick(()=>{ console.log('執行mounted建立的this.$nextTick()函數') }) }, methods: { // 更新數據 updateDate(){ }, get(){ this.value='更新data內的value屬性值' // 獲取頁面元素數據 console.log(this.$refs['example').innerText) this.$nextTick(()=>{ console.log(this.$refs['example'].innerText) }) } }
var vm=new Vue({})
表示開始建立一個Vue
的實例對象,init events&liftcycle
表示剛初始化了一個vue
空的實例對象,這個時候,對象身上,只有默認的一些生命週期函數和默認事件,其餘東西都沒有建立,beforeCreate
生命週期函數執行的時候,data
和methods
中的數據都沒有初始化。在created
中,data
和methods
都已經被初始化好了,若是要調用methods
中的方法,或者操做data
中的數據,只能在created
中操做。而後vue
開始編輯模板,把vue
代碼中的那些指令進行執行,最終在內存中生成一個編譯好的最終模板字符串,渲染爲內存中的dom
,此時只是在內存中,渲染好了模板,並無把模板掛載到真正的頁面中去。beforeMount
函數執行的時候,模板已經在內存中編譯好了,可是還沒有掛載到頁面中去。create vm.$el and replace 'el' with it
這一步是將內存中編譯好的模板,真實的替換到瀏覽器的頁面中去。mounted
,只要執行完了mounted
,就表示整個vue
實例已經初始化完了。此時,組件從建立階段進入到了運行階段。
beforeUpdate
執行的時候,頁面中顯示的數據還舊的,而data
數據是最新的,頁面還沒有和最新的數據保持同步。updated
事件執行的時候,頁面和data
數據已經保持同步了,都是新的。virtual dom re-render and patch
執行,先根據data
中最新的數據,在內存中,從新渲染出一份最新的內存dom
樹,當最新的內存dom
樹被更新以後,會把最新的內存dom
樹,從新渲染到真實的頁面中,完成數據從data
到view
的跟新。
beforeDestroy
鉤子函數執行時,vue
實例就從運行階段,進入到了銷燬階段。此時的實例仍是可用的階段,沒有真正執行銷燬過程。destroyed
函數執行時,組件已經被徹底銷燬了,都不可用了。
mvvm
的理解雙向綁定的過程
視圖view
,路由-控制器Controller
,數據Model
view
->dom
,viewModel
,Model
數據
傳統的mvc
指用戶操做會請求服務器端路由,路由會調用對應的控制器來處理,控制器會獲取數據,將結果返回給前端,讓頁面從新渲染。
mvvm
,對於傳統的前端會將數據手動渲染到頁面上,mvvm
模式不須要用戶收到操做dom
元素,將數據綁定到viewModel
層上,會自動將數據渲染到頁面中,視圖變化會通知viewModel
層更新數據。
vue
內部是如何監聽message
數據的改變vue
是如何知道要通知哪些人,界面發生刷新核心:
Object.defineProperty
,監聽對象屬性的改變代碼:
Object.keys(obj).forEach(key => { let value = obj[key] Object.defineProperty(obj, key, { set(newValue) { // 監聽改變 value = newValue }, get() { return value } }) }) obj.name = 'web'
發佈者訂閱者
class Dep { constructor() { this.subs = [] } } class Watcher { constructor(name) { this.name = name; } }
對象的Object.defindeProperty
中的訪問器屬性中的get
和set
方法
getter
和setter
,創建watcher
並收集依賴。說明:
watcher
經過回調函數更新view
;observer
觀測data
數據,經過get
通知dep
收集watcher
,dep
經過notify()
通知watcher
數據更新,watcher
經過addDep()
收集依賴。
Observer
:用於監聽劫持全部data
屬性,dep,watcher,view
,Compile
解析el
模板中的指令。
依照下圖(參考《深刻淺出vue.js
》)
首先從初始化data
數據開始,使用Observer
監聽數據,個體每一個數據屬性添加Dep
,而且在Data
,有兩個getter
,setter
。在它的getter
過程添加收集依賴操做,在setter
過程添加通知依賴的操做。
在解析指令或者給vue
實例設置watch選項或者調用$watch
時,生成對應的watcher
並收集依賴。
Data
經過Observer
轉換成了getter/setter
的形式,來對數據追蹤變化。
修改對象的值的時候,會觸發對應的setter
,setter
通知以前依賴收集獲得的 Dep
中的每個Watcher
,告訴它們值改變了,須要從新渲染視圖。
數據雙向綁定原理
Object.defineProperty
vue
在初始化數據時,會給data
中的屬性使用Object.defineProperty
從新定義全部屬性,當頁面取到對應屬性時,會進行依賴收集,若是屬性發生變化會通知相關依賴進行更新操做。initData
初始化用戶傳入的data
數據,new Observer
將數據進行觀測,this.walk(value)
進行對象的處理,defineReactive
循環對象屬性定義響應式變化,Object.defineProperty
,使用Object.defineProperty
從新定義數據。
使用使用Object.defineProperty
從新定義數據的每一項。
Object.defineProperty(obj,key,{ enumerable: true, configurable: true, get: function reactiveGetter(){ const value=getter?getter.call(obj):val if(Dep.target){ dep.depend() if(childOb){ childOb.dep.depend() if(Array.isArray(value)){ dependArray(value) } } } return value }, set: function reactiveSetter(newVal) { const value=getter?getter.call(obj).val if(newVal === value || (newVal !== newVal && value !==value)){ return } if(process.env.NODE_ENV !== 'production' && customSetter){ customSetter() } val = newVal childOb = !shallow && observe(newVal) dep.notify() } })
使用函數劫持的方式,重寫了數組的方法,vue
將data
中的數組進行了原型鏈的重寫,指向了本身定義的數組原型方法,這樣當調用數組api
時,能夠通知依賴跟新,若是數組中包含着引用類型,會對數組中的引用類型再次進行監控。
initData
初始化用戶傳入的data
數據,new Observer
將數據進行觀測,protoAugment(value,arrayMethods)
將數據的原型方法指向重寫的原型。
observerArray
深度觀察數組中的每一項代碼:
if(Array.isArray(value)){ // 判斷數組 if(hasProto){ protoAugment(value, arrayMethods)// 改寫數組原型方法 }else{ copyAugment(value,arrayMethods,arrayKeys) } this.observeArray(value) //深度觀察數組中的每一項 }else{ this.walk(value) // 從新定義對象類型數據 } function protoAugment(target, src: Object){ target.__proto__ = src } export const arrayMethods = Object.create(arrayProto) const methodsToPatch=[ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ] methodsToPatch.forEach(function (method){ const original = arrayProto[method] def(arrayMethods, method, function mutator(...args){ const result = original.apply(this.args) const ob = this.__ob__ let inserted switch(method) { case 'push': case 'unshift': inserted = args break case 'splice': inserted = args.slice(2) break } if(inserted) ob.observerArray(inserted) // 對插入的數據再次進行觀測 ob.dep.notify() // 通知視圖更新 return result } } observeArray(items: Array<any>) { for(let i=0, l = items.length; i<1; i++) { observe(item[i]) // 觀測數組中的每一項 } }
若是不採用異步更新,每次更新數據都會對當前組件進行從新渲染,爲了性能考慮。
dep.notify()
通知watcher
進行更新操做,subs[i].update()
依次調用watcher
的update
,queueWatcher
將watcher
去重放到隊列中,nextTick(flushSchedulerQueue)
異步清空watcher
隊列。
微任務高於宏任務先執行
nextTick
方法主要使用了宏任務和微任務,定義了一個異步方法,屢次調用了nextTick
會將方法存入到隊列中,經過這個異步方法清空當前隊列。
nextTick
方法是異步方法。
原理:nextTick(cb)
調用nextTick
傳入cb
,callbacks.push(cb)
將回調存入數組中,timerFunc()
調用timerFunc
,返回promise
支持promise
的寫法。
什麼是webpack,webpack是一個現代的JavaScript應用的靜態模塊打包工具。
webpack是前端模塊化打包工具
安裝webpack須要安裝node.js,node.js自帶有軟件包管理工具npm
全局安裝
npm install webpack@3.6.0 -g
局部安裝
npm install webpack@3.6.0 --save-dev
webpack.config.js
固定名文件:
const path = require("path") module.exports = { entry: './src/main.js', output: { patch: './dist', filename: '' }, }
package.json
{ "name": 'meetwebpack', "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo ..." }, "author": "", "license": "ISC" }
什麼是loader
loader
是webpack
中一個很是核心的概念
loader
使用過程:
npm
安裝須要使用的loader
webpack.config.js
中的moudules
關鍵字下進行配置package.json
中定義啓動
{ "name": "meetwebpack", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "webpack" }, "author": "", "license": "ISC", "devDependencies": { "webpack": "^3.6.0" } }
webpack
的介紹webpack
能夠看作是模塊打包機,它能夠分析你的項目結構,找到JavaScript模塊以及其它的一些瀏覽器不能直接運行的拓展語言,將其打包爲合適的格式以供瀏覽器使用。
能夠實現代碼的轉換,文件優化,代碼分割,模塊合併,自動刷新,代碼校驗,自動發佈。
安裝本地的webpack
webpack webpack-cli -D
初始化:
yarn init -y
yarn add webpack webpack-cli -D
webpack能夠進行0配置,它是一個打包工具,能夠輸出後的結果(Js模塊),打包(支持js的模塊化)
運行webpack命令打包
npx webpack
webpack.config.js
,webpack
是node
寫出來的node
的寫法:
let path = require('path') console.log(path.resolve('dist'); module.exports = { mode: 'development', // 模式,默認兩種,production,development entry: '' // 入口 output: { filename: 'bundle.js', // 打包後的文件名 path: path.resolve(__dirname, 'build'), // 把相對路徑改寫爲絕對路徑 } }
自定義,webpack.config.my.js
使用命令:
npx webpack --config webpack.config.my.js
package.json
:
{ "name": 'webpack-dev-1', "version": "1.0.0", "main": "index.js", "license": "MIT", "scripts": { "build": "webpack --config webpack.config.my.js" }, "devDependencies": { "webpack": "^4.28.3", "webpack-cli": "^3.2.0" } }
使用命令:
npm run build // npm run build -- --config webpack.config.my.js
開發服務器的配置
代碼:
let path = require('path') let HtmlWebpackPlugin = require('html-webpack-plugin') console.log(path.resolve('dist'); module.exports = { devServer: { // 開發服務器的配置 port: 3000, // 看到進度條 progress: true, contentBase: "./build", compress: true }, mode: 'development', // 模式,默認兩種,production,development entry: '' // 入口 output: { filename: 'bundle.js', // 打包後的文件名 path: path.resolve(__dirname, 'build'), // 把相對路徑改寫爲絕對路徑 }, plugins: [ // 數組,全部的webpack插件 new HtmlWebpackPlugin({ template: './src/index.html', filename: 'index.html', minify:{ removeAttributeQuotes: true,//刪除「」 collapseWhitespace: true, // 變成一行 }, hash: true }) ], module: { // 模塊 rules: [ // 規則 {test: /\.css$/, use: [{ loader: 'style-loader', options: { insertAt: 'top' } },'css-loader'] }, ] } }
output: { filename: 'bundle.[hash:8].js',// 打包文件名後只顯示8位 }
{ "name": 'webpack-dev-1', "version": "1.0.0", "main": "index.js", "license": "MIT", "scripts": { "build": "webpack --config webpack.config.my.js", "dev": "webpack-dev-server" }, "devDependencies": { "webpack": "^4.28.3", "webpack-cli": "^3.2.0" } }
yarn add css-loader style-loader -D
樣式:
style-loader
將模塊的導出做爲樣式添加到dom
中css-loader
解析css
文件後,使用import
加載,而且返回css
代碼less-loader
加載和轉譯less
文件sass-loader
加載和轉譯sass/scss
文件postcss-loader
使用PostCSS
加載和轉譯css/sss
文件stylus-loader
加載和轉譯Stylus
文件style-loader
安裝:
npm install style-loader --save-dev
用法:
建議將style-loader
與css-loader
結合使用
component.js
import style from './file.css'
css-loader
只負責將css文件進行加載style-loader
負責將樣式添加到dom
中loader
時,是從右到左代碼:
// webpack.config.js module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'] } ] }
css
文件處理:style-loader
安裝style-loader
npm install --save-dev style-loader
style-loader
須要放在css-loader
的前面,webpack
在讀取使用的loader
的過程當中,是按照從右向左的順序讀取的。
webpack.config.js
的配置以下:
const path = require('path') module.exports = { // 入口:能夠是字符串/數組/對象,這裏咱們入口只有一個,因此寫一個字符串便可。 entry: './src/main.js', // 出口:一般是一個對象,裏面至少包含兩個重要屬性,path和filename output:{ path: path.resolve(__dirname, 'dist'), // 注意:path一般是一個絕對路徑 filename: 'bundle.js' }, module: { rules: { { test: /\.css$/, use: ['style-loader','css-loader'] } } } }
webpack
less文件處理安裝:
npm install --save-dev less-loader less
示例:
將css-loader
,style-loader
,less-loader
鏈式調用,能夠把全部樣式當即應用於dom
。
// webpack.config.js module.exports = { ... rules: [{ test: /\.less$/, use: [{ loader: 'style-loader' },{ loader: 'css-loader' },{ loader: 'less-loader' }] }] }
圖片文件處理
css normal
代碼:
body { background: url("../img/test.jpg") }
url-loader
npm install --save-dev url-loader
用法
url-loader
功能相似於file-loader
,可是在文件大小低於指定的限制時,能夠返回一個DataURL
import img from './image.png'
webpack.config.js
module.exports = { module: { rules: [ { test: /\.(png|jpg|gif)$/, use: [ { loader: 'url-loader', options: { limit: 8192 } } ] } ] } }
img
,文件要打包到的文件夾
name
,獲取圖片原來的名字,放在該位置
hash:8
,爲了防止圖片名稱衝突,依然使用hash
,可是咱們只保留8位
ext
,使用圖片原來的擴展名
若是但願es6轉成es5,那麼就須要使用babel
npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
配置webpack.config.js
文件:
{ test: /\.m?js$/, use: { loader: 'babel-loader', options: { presets: ['es2015'] } } }
如何在咱們的webpack
環境中集成vue.js
代碼:
npm install vue --save
runtime-only
代碼中,不能夠有任何的template
runtime-compiler
代碼中,能夠有template
由於有compiler
能夠用於編譯template
spa
(simple age web application
)->vue-router
(前端路由)
.vue
文件封裝處理
安裝vue-loader
和vue-template-compiler
npm install vue-loader vue-template-compiler --save-dev
plugin
是什麼?plugin
是插件的意思,一般用於對某個現有的架構進行擴展。webpack
中的插件,是對webpack
現有功能的各類擴展。loader
和plugin
的區別loader
主要用於轉換某些類型的模塊,它是一個轉換器。plugin
是插件,它是對webpack
自己的擴展,是一個擴展器。plugin
的使用過程:npm
安裝須要使用的plugins
webpack.config.js
中的plugins
中配置插件webpack.config.js
的文件:
查看bundle.js
文件的頭部:
什麼是vue cli
,Command-Line Interface
,命令行界面,俗稱腳手架,vue cli
是一個官方發佈的項目腳手架。使用vue-cli
能夠快速搭建vue
開發環境以及對應的webpack
配置。
vue cli
的使用
安裝vue
腳手架
npm install -g @vue/cli
代碼:
vue init webpack vuecli2test
Project name
項目名稱,不能包含大寫Project description
項目描述Author
做者信息Vue build
`runtime`Install vue-router
`no`是否安裝等目錄結構詳解
build
`config 是
webpack相關配置,
node_modules 是依賴的
node相關的模塊,
src是寫代碼地方。
.babelrc是es代碼相關轉換配置,
.editorconfig項目文本相關配置,
.gitignore`git
倉庫忽略的文件夾配置,.postcssrc.js
爲css
相關轉化的配置。
.editorconfig
前端模塊化:
爲何使用模塊化,簡單寫js代碼帶來的問題,閉包引發代碼不可複用,本身實現了簡單的模塊化,es
中模塊化的使用:export
和import
。
npm install @vue/cli -g
npm clean cache -force
vue cli2
初始化:
vue init webpack my-project
vue cli3
初始化項目:
vue create my-project
箭頭函數,是一種定義函數的方式
function
const a = function(){ }
const obj = { b: function() { }, b() { } }
const c = (參數列表) => { } const c = () => { }
箭頭函數參數和返回值
代碼:
const sum = (num1, num2) => { return num1 + num2 } const power = (num) => { return num * num } const num = (num1,num2) => num1 + num2
const obj = { a() { setTimeout(function() { console.log(this); // window }) setTimeout(()=>{ console.log(this); // obj對象 }) } }
路由,,vue-router
基本使用,vue-router
嵌套路由,vue-router
參數傳遞,vue-router
導航守衛。
路由是一個網絡工程裏面的術語,路由就是經過互聯的網絡把信息從源地址傳輸到目的地址的活動。
路由器提供了兩種機制:路由和轉送。路由是決定數據包歷來源到目的地的路徑,轉送將輸入端的數據轉移到合適的輸出端。路由中有一個很是重要的概念叫路由表。路由表本質上就是一個映射表,決定了數據包的指向。
後端路由:後端處理url和頁面之間的映射關係。
vue-router
和koa-router
的區別:
vue-router
是前端路由,koa-router
是後端路由。
vue-router
前端路由原理:
前端路由主要模式:hash
模式和history
模式。
路由的概念來源於服務端,在服務端中路由描述的是 URL 與處理函數之間的映射關係。
先後端渲染之爭
hash
和html5
的history
前端路由的核心是改變url
,可是頁面不進行總體的刷新。單頁面,其實spa
最重要的特色就是在先後端分離的基礎上加了一層前端路由。就是前端來維護一套路由規則。
url
的hash
url
的hash
是錨點#
,本質上是改變window.location
的href
屬性。直接賦值location.hash
來改變href
,可是頁面不發生刷新。
html5
的history
模式:pushState
html5
的history
模式:replaceState
html5
的history
模式:go
history.go()
history.back()
等價於history.go(-1)
history.forward()
等價於history.go(1)
安裝vue-router
npm install vue-router --save
Vue.use(VueRouter)
Vue
實例中掛載建立的路由實例代碼:
// 配置路由相關的信息 import VueRouter from 'vue-router' import vue from 'vue' import Home from '../components/Home' import About from '../components/About' // 經過Vue.use(插件),安裝插件 Vue.use(VueRouter) // 配置路由和組件之間的應用關係 const routes = [ { path: '/home', component: Home }, { path: '/about', component: About } ] // 建立VueRouter對象 const router = new VueRouter({ routes }) // 將router對象傳入到`Vue`實例 export default router
main.js
import Vue from 'vue' import App from './App' import router from './router' Vue.config.productionTip = false new Vue({ el: '#app', router, render: h => h(App) })
使用vue-router
的步驟
<router-link>
和<router-view>
代碼:
組件components
// home <template> <div> <h2>我是首頁</h2> </div> </template> <script> export default { name: 'Home' } </script> <style scoped> </style>
<template> <div> <h2>我是關於</h2> </div> </template> <script> export default { name: 'Aboout' } </script> <style scoped> </style>
App.vue
<template> <div id="app"> <router-link to="/home">首頁</router-link> <router-link to="/about">關於</router-link> <router-view></router-view> </div> </div> <script> export default { name: 'App' } </script> <style> </style>
main.js
import Vue from 'vue' import App from './App' import router from './router' Vue.config.productionTip = false new Vue({ el: '#app', router, render: h => h(App) })
路由的偶然值和修改成
history
模式
建立router
實例
代碼:
router->index.js
import Vue from 'vue' import VueRouter from 'vue-router' // 注入插件 Vue.use(VueRouter) // 定義路由 const routes = [] // 建立router實例 const router = new VueRouter({ routes }) // 導出router實例 export default router
main.js
代碼:
import Vue from 'vue' import App from './App' import router from './router' new Vue({ el: '#app', router, render: h=>h(App) })
router->index.js
import Vue from 'vue' import VueRouter from 'vue-router' import Home from '../components/home' import About from '../components/about' // 注入插件 Vue.use(VueRouter) // 定義路由 const routes = [ { path: '/home', component: Home }, { path: '/about', component: About } ]
使用App.vue
代碼
<template> <div id="app"> <router-link to="/home">首頁</router-link> <router-link to="/about">關於</router-link> <router-view></router-view> </div> </template> <script> export default { name: 'App', components: { } }
<router-link>
該標籤是一個vue-router
已經內置的組件,它會被渲染成一個<a>
標籤<router-view>
該標籤會根據當前的路徑,動態渲染出不一樣的組件。<router-view>
處於同一個等級。<router-view>
掛載的組件,其餘內容不會發生改變。路由的默認路徑
默認狀況下,進入網站的首頁,<router-view>
渲染首頁的內容,可是默認沒有顯示首頁組件,必須讓用戶點擊才能夠。
那麼如何讓路徑默認跳轉到首頁,而且<router-view>
渲染首頁組件呢,只須要配置一個映射就能夠:
const routes = [ { path: '/', redirect: '/home' } ]
配置解析:在routes
中又配置了一個映射,path
配置的是根路徑:/
,redirect
是重定向,就是咱們將根路徑重定向到/home
的路徑下。
// main.js const router = new VueRouter({ // 配置路由和組件之間的應用關係 routes, mode: 'history' })
改變路徑的方式:
url
的hash
html5
的history
url
的hash
使用html5
的history
模式:
// 建立router實例 const router = new VueRouter({ routes, mode: 'history' })
router-link
,使用了一個屬性:to
,用於指定跳轉的路徑。tag
能夠指定<router-link>
以後渲染成什麼組件。
replace
屬性不會留下history
記錄,指定replace
的狀況下,後退鍵返回不能返回到上一個頁面中。
active-class
屬性,當<router-link>
對應的路由匹配成功時,會自動給當前元素設置一個router-link-active
的class
,設置active-class
能夠修改默認的名稱。
const router = new VueRouter({ routes, mode: 'history', linkActiveClass: 'active' })
App.vue
代碼:
// app.vue <template> <div id="app"> <button @click="linkToHome">首頁</button> <button @click="linkToAbout">關於</button> <router-view></router-view> </div> </template> <script> export default { name: 'App', methods: { linkToHome() { this.$router.push('/home') }, linkToAbout() { this.$router.push('/about') } } } </script>
<img :src="imgURL" alt=""> <router-link :to="'/uer/' + userId"> 用戶 </router-link> <script> export default { name: 'User', computed: { userId() { return this.$route.params.userId } } } </sript>
const Home = () => import('../components/Home') const HomeNews = () => import('../components/HomeNews') const HomeMessage = () => import('../components/HomeMessage') { path: '/home', component: Home, children: [ { path: 'news', component: HomeNews }, { path: 'news', component: HomeMessage } ] }
<router-link to = "/home/news">新聞</router-link> <router-link to = "/home/message">信息</router-link>
默認選中:
傳遞參數主要有兩種類型,params
和query
params
的類型:
/router/:id
path
後面跟着對應的值/router/123
vue-router
傳遞參數代碼
<router-link :to="{path: '/profile'}">用戶</router-link>
統一資源定位符
統一資源定位符,統一資源定位器,統一資源定位地址,Url地址等,網頁地址。如同在網絡上的門牌,是因特網上標準的資源的地址。
userClick() { this.$router.push('/user/' + this.userId) } btnClick() { this.$router.push({ path: '/user', query: { name: 'web', age: 12, height: 1.2 } }) }
$route
和$router
是有區別的
獲取參數經過$route
對象獲取的,在使用vue-router
的應用中,路由對象會被注入每一個組件中,賦值爲this.$route
,而且當路由切換時,路由對象會被更新。
<template> <div> <p> {{$route.params}} </p> </div> </template>
query
的類型:
/router
也是普通配置query
的key
做爲傳遞方式router?id=123
,/router?id=abc
$route
和$router
是有區別的
const router = new VueRouter({ routes, mode: 'history', linkActiveClass: 'active' })
Vue.config.productionTip = false Vue.prototype.test = function() { console.log('test') } Vue.prototype.name = 'web'
$route
和$router
是有區別的
$router
爲VueRouter
實例,想要導航到不一樣url
,則使用$router.push
方法。$route
爲當前router
跳轉對象裏面能夠獲取name
,path
,query
,params
等。vue-router
全局導航
meta:元數據
router.beforeEach((to,from,next) => { // from 跳轉到to document.title = to.matched[0].meta.title console.log(to); next() })
// 後置鉤子hook router.afterEach((to,from) => { console.log(); })
導航守衛:導航表示路由正在發生改變。
vue-router
提供的導航守衛主要用來經過跳轉或取消的方式守衛導航。有多種機會植入路由導航過程當中,全局的,單個路由獨享的,或者組件級的。
全局守衛
可使用router.beforeEach
,註冊一個全局前置守衛:
const router = new VueRouter({..}) router.beforeEach((to,from,nex)=>{ })
當一個導航觸發時,全局前置守衛按照建立順序調用。守衛是異步解析執行,此時導航在全部守衛resolve
完以前一直處於等待中。
to:Route
,即將要進入的目標路由對象from:Route
,當前導航正要離開的路由next:Function
,必定要調用該方法來resolve
這個鉤子。vue-router-keep-alive
keep-alive
和vue-router
router-view
是一個組件,若是直接被包含在keep-alive
裏面,全部路徑匹配到的視圖組件都會被緩存。
keep-alive
是Vue
內置的一個組件,可使被包含的組件保留狀態,或避免從新渲染。
屬性:
include
字符串或正則表達式,只有匹配的組件會被緩存exclude
字符串或正則表達式,任何匹配的組件都不會被緩存<keep-alive> <router-view> // 全部路徑匹配到的視圖組件都會被緩存 </router-view> <keep-alive>
Promise
的使用es6
的特性Promise
,它是異步編程的一種解決方案。
定時器的異步事件:
setTimeout(function() { let data = 'web' console.log(content) },1000) new Promise((resolve, reject) => { setTimeout(function(){ resolve('web') reject('error') },1000) }).then(data=>{ console.log(data) }).catch(error=> { console.log(error) })
Promise
三種狀態:
pending
等待狀態,好比正在進行網絡請求,或定時器沒有到時間。fulfill
,知足狀態,主動回調resolve
時,而且回調.then()
reject
,拒絕狀態,回調reject
時,而且回調.catch()
vuex
是一個專門爲vue.js
應用程序開發的狀態管理模式
它採用集中式存儲管理應用的全部組件的狀態,,並以相應的規則保證狀態以一種可預測的方式發生變化。
View components -> actions(dispatch方式) -> mutations(commit方式) -> state -> View components
Vuex
核心概念5個:
State
,Getters
,Mutation
,Action
,Module
State
單一狀態樹,單一數據源。
Mutation
狀態更新
Vuex
的store
的更新惟一方式,提交Mutation
Mutation
的主要包括兩部分:
state
mutation
的定義:
mutations: { increment(state) { state.count++ } }
經過mutation
更新
increment: function() { this.$store.commit('increment') }
參數被稱爲是mutation
的載荷payload
Vuex
的store
中的state
是響應式的,當state
中的數據發生改變時,Vue
組件會自動更新。
store
中初始化好所需的屬性state
中的對象添加新屬性時:使用Vue.set(obj,'newObj',123)
Mutation
常量類型
// mutation-types.js export const UPDATE_INFO = 'UPDATE_INFO' import Vuex from 'vuex' import Vue from 'vue' import * as types from './mutation-types' Vue.use(Vuex) const store = new Vuex.Store({ state: { info: { name: 'web', age: 12 } }, mutations: { [types.UPDATE_INFO](state, payload) { state.info = {...state.info, 'height': payload.height } } })
<script> import {UPDATE_INFO} from './store/mutation-types'; export default{ name: 'App', components: { }, computed: { info(){ return this.$store.state.info } }, methods: { updateInfo(){ this.$store.commit(UPDATE_INFO,{height:1.00}) } } } </script>
注意:不要再mutation
中進行異步操做,mutation
同步函數,在其中的方法必須時同步方法。
action
的基本定義,若是有異步操做,好比網絡請求,
// 不能再mutation中使用異步操做,不能再這裏進行異步操做 update(state) { setTimeout(()=>{ state.info.name = 'web' },1000) } mutations: { // 方法 [INCREMENT](state){ state.counter++ } }
actions: { // context:上下文,=》store <!--aUpdateInfo(context) {--> <!-- setTimeout(()=>{--> <!-- state.info.name = 'web'--> <!-- },1000)--> <!--}--> }
actions: { aUpdateInfo(context) { setTimeout(()=>{ context.commit('updateInfo') },1000) } } // xx.vue updateInfo(){ this.$store.dispatch('aUpdateInfo') }
updateInfo(){ <!--this.$store.commit('updateInfo')--> this.$store.dispatch('aUpdateInfo',{ message: 'web', success: () => { console.log('web') } }) }
aUpdateInfo(context, payload) { return new Promise((resolve, reject) => {...}) }
modules時模塊的意思
getters: { stu(){ }, stuLength(state, getters) { return getters.stu.length } }
使用根數據:
getters: { fullName(state) { return state.name + '1' }, fullName1(state, getters) { return getters.fullName + '2' }, fullName3(state, getters, rootState) { return getters.fullName2+rootState.counter } }
在模塊中actions
打印console.log(context)
actions
接收一個context
參數對象,局部狀態經過context.state
暴露出來,根節點狀態爲context.rootState
import mutations from './mutations' import actions from './actions' import getters from './getters' import moduleA from './modules/moduleA' import Vuex from 'vuex' import Vue from 'vue' Vue.use(Vuex) const state = { } const store = new Vuex.Store({ state, mutations, actions, getters, modules: { a: moduleA } }) export default store
axios網絡模塊的封裝
ajax
是基於XMLHttpRequest(XHR)
;jQuery-Ajax
相對於傳統的ajax
很是好用。
axios
特色:
XMLHttpRequests
請求node.js
中發送http
請求Promise API
axios
請求方式:
axios(config) axios.request(config) axios.get() axios.delete() axios.head() axios.post() axios.put() axios.patch()
安裝
npm install axios --save
axios({ // 默認get url: '', method: 'get' }).then(res=>{ console.log(res) })
// import request from "../utils/request.js" import {request} from './network' export function getHome() { return request({ url: '/home/xxx' }) } export function getXX(type, page) { return request({ url: '/home/xx', params: { type, page } }) }
併發請求
代碼:
axios.all([axios({ url: '' }), axios({ url: '', params: { type: '', page: 1, } })]).then(results => { }) // then(axios.spread((res1,res2)=>{...}))
全局配置
axios.defaults.baseURL='' axios.all ..{ url: '/home' } axios.defaults.baseURL = 'https://api.example.com'; axios.defaults.headers.common['Authorization'] = AUTH_TOKEN; axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; axios.defaults.baseURL = global.HOST;
request.js
import axios from 'axios' export function request(config,success,failure){ // 建立axios實例 const instance = axios.create({ baseURL: '', timeout: 5000 }) // 發送網絡請求 instance(config) .then(res=>{ success(res) }) .catch(err=>{ failure(err) }) }
main.js
import {request} from './xx/request' request({ url: '' },res=>{ ),err=>{ }
也可使用promise
方法,不過自己返回的就是promise
import axios from 'axios' export function request(config) { const instance = axios.create({ baseURL: '', timeout: 2000 }) return instance(config) }
axios
攔截器的使用
// 配置請求和響應攔截 instance.interceptors.request.use(config => { console.log('request攔截success中') return config },err => { console.log('request攔截failure中') return err }) instance.interceptors.response.use(response => { console.log('response攔截success中') return response.data },err => { console.log('response攔截failure中') return err })
封裝axios
// request.js import axios from 'axios' cosnt service = axios.create({ baseURL: process.env.BASE_API, timeout: 2000 }) service.interceptors.request.use(config=>{ //發請求前作的一些處理,數據轉化,配置請求頭,設置token,設置loading等 config.data=JSON.stringify(config.data); config.headers = { 'Content-Type':'application/x-www-form-urlencoded' } return config },error=>{ Promise.reject(error) }) // 響應攔截器 service.interceptors.response.use(response => { return response }, error => { if (error && error.response) { switch (error.response.status) { case 400: error.message = '錯誤請求' break; case 401: error.message = '未受權,請從新登陸' break; case 403: error.message = '拒絕訪問' break; case 404: error.message = '請求錯誤,未找到該資源' window.location.href = "/NotFound" break; case 405: error.message = '請求方法未容許' break; case 408: error.message = '請求超時' break; case 500: error.message = '服務器端出錯' break; case 501: error.message = '網絡未實現' break; case 502: error.message = '網絡錯誤' break; case 503: error.message = '服務不可用' break; case 504: error.message = '網絡超時' break; case 505: error.message = 'http版本不支持該請求' break; default: error.message = `鏈接錯誤${error.response.status}` } } else { if (JSON.stringify(error).includes('timeout')) { Message.error('服務器響應超時,請刷新當前頁') } error.message('鏈接服務器失敗') } Message.error(err.message) return Promise.resolve(error.response) }) // 導入文件 export default service
封裝請求http.js
import request from './request' const http ={ /** * methods: 請求 * @param url 請求地址 * @param params 請求參數 */ get(url,params){ const config = { methods: 'get', url:url } if(params){ config.params = params } return request(config) }, post(url,params){ const config = { methods: 'post', url:url } if(params){ config.data = params } return request(config) }, put(url,params){ const config = { methods: 'put', url:url } if(params){ config.params = params } return request(config) }, delete(url,params){ const config = { methods: 'delete', url:url } if(params) { config.params = params } return request(config) } } export default http
// api.js import http from '../utils/http' let resquest = "/xx/request/" // get請求 export function getListAPI(params){ return http.get(`${resquest}/getList.json`,params) } // js //建立新的axios實例, const service = axios.create({ baseURL: process.env.BASE_API, timeout: 3 * 1000 })
建立項目:
vue create webMall npm run serve
// .editorconfig root = true [*] charset = utf-8 indent_style=space indent_size = 2 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true
項目在
window
下部署
main.js
代碼:
import store from './store' import FastClick from 'fastclick' import VueLazyLoad from 'vue-lazyload' import toast from 'components/common/toast' Vue.config.productionTip = false // 添加事件總線對象 Vue.prototype.$bus = new Vue() // 安裝toast插件 Vue.use(toast) // 解決移動端300ms延遲 FastClick.attach(document.body) // 使用懶加載的插件 Vue.use(VueLazyLoad,{ loading: require('./xx.png') })
windows
安裝nginx
,linux
部署,centos
上安裝nginx
linux ubuntu
Ubuntu
是一個以桌面應用爲主的Linux
操做系統,其名稱來自非洲南部祖魯語或豪薩語的「ubuntu"
一詞。
操做系統:Window10 + Centos6.5(虛擬機)
yum install nginx systemtl start nginx.service systemctl enable nginx.service
經過Xftp將vue項目文件上傳至雲服務器
使用Xshell鏈接雲服務器
主機就是阿里雲上建立的實例的公網ip
輸入登陸名和密碼,登陸名就是購買服務器時輸入的登陸名和密碼。
運行npm run build
命令,有一個dist文件夾,這就是vue項目打包後的文件。
nginx安裝配置
在Xshell
終端輸入命令yum install nginx
,當須要確認時輸入」y「
回車。
安裝完成後,輸入service nginx start
啓動nginx
服務。
經過命令nginx -t
查看nginx
所在的安裝目錄。
在命令行輸入命令cd/etc/nginx
切換到nginx
目錄下,再輸入cat nginx.conf
可查看當前nginx
配置文件。
輸入命令 wget https://nodejs.org/dist/v10.8.0/node-v10.8.0-linux-x64.tar.xz
回車,等待安裝。
輸入命令tar xvf node-v10.8.0-linux-x64.tar.xz
回車進行解壓操做。
stop
,prevent
,.enter
,.once
,.native
等,lazy
,number
,trim
等。script
,template
props
,子傳父,$emit
npm install
,npm run serve
webStorm
開發vue
在Plugins
安裝插件vue.js
2.6.0
版本中,Vue
爲具名插槽和做用域插槽引入了一個新的統一的語法 (即 <v-slot>
指令)。它取代了 slot
和 slot-scope
這兩個目前已被廢棄、還沒有移除,仍在文檔中的特性。v-slot
用法,分爲三類:默認插槽、具名插槽以及做用域插槽。做用域插槽,經過 slot-scope
屬性來接受子組件傳入的屬性集合
代碼:
// 子組件 <template> <div> <header> <slot>默認值</slot> </header> </div> </template>
任何沒有被包裹在帶有v-slot
的<template>
中的內容都會被視爲默認插槽的內容。當子組件只有默認插槽時,<v-slot>
標籤能夠直接用在組件上
// 父組件 <template> <div> <child> 內容1 <template>內容2</template> 內容3 </child> <child v-slot="web"> 插槽<br> 插槽<br> </child> </div> </template>
v-slot
重複定義一樣的 name
後只會加載最後一個定義的插槽內容// 子組件 <template> <div> <main> <slot name="main"></slot> </main> <footer> <slot name="footer"></slot> </footer> </div> </template>
// 子組件 <template> <div> <footer> <slot name="footer" :user="user" :testBtn="testBtn"> {{user.name}} </slot> </footer> </div> </template> <script> exportdefault { name: 'child', data () { return { user: { title: 'web', name: 'web' } }; }, methods:{ testBtn(){ alert('web'); } } }; </script>
Vue
如何直接調用Component
裏的方法
<template> <div> <b-component ref="BComponent"></b-component> </div> </template> <script> import BComponent from './BComponent' export default { name: 'A', data () { }, components: { BComponent }, methods: { callACompoentFunction () { this.$refs.BComponent.sayHi() } } } </script> <style scoped> </style>
<template> <div></div> </template> <script> export default { name: 'B', data () { }, methods: { sayHi () { console.log('web!') } } } </script> <style scoped> </style>
我是程序員哆啦A夢,藍胖子,簡書萬粉優秀創做者,掘金優秀做者、CSDN博客專家,雲+社區社區活躍做者,致力於打造一系列可以幫助程序員提升的優質文章。網站@http://www.dadaqianduan.cn