Vue項目經驗javascript
setInterval路由跳轉繼續運行並無及時進行銷燬
好比一些彈幕,走馬燈文字,這類須要定時調用的,路由跳轉以後,由於組件已經銷燬了,可是setInterval尚未銷燬,還在繼續後臺調用,控制檯會不斷報錯,若是運算量大的話,沒法及時清除,會致使嚴重的頁面卡頓。
解決方案:在組件生命週期beforeDestroy中止setInterval
beforeDestory() {
clearInterval(this.timer);
MessageBox.close()
}php
使用vue過程當中你遇到了什麼困難?
多級嵌套傳參,解決思路自行百度
路由嵌套
路由嵌套會將其餘組件渲染到該組件內,而不是進行整個頁面跳轉router-view自己就是將組件渲染到該位置,想要進行頁面跳轉,就要將頁面渲染到根組件,在起始配置路由時候寫到:
var App = Vue.extend({ root });
router.start(App,'#app');
這裏首先將根組件註冊進來,用於將路由中配置好的各個頁面渲染出來,而後將根組件掛載到與#app匹配的元素上。css
組件的異步加載(按需加載組件)
在平時的demo中,你可能不會碰見這個需求,當頁面不少,組件不少的時候,你會發現你的頁面在首次加載的時候,異常的慢,這個是由於vue首次加載的時候把可能一開始看不見的組件也一次加載了,這個時候就須要對頁面優化了,就須要異步組件了。如何去寫異步組件呢,實際上很簡單,只須要在你的路由index,js里加上require就能夠了,像下面這樣,這也是所謂的按需加載組件的實現原理。html
vuejs構建組件使用
Vue.component('componentName',{ /*component*/ });
這裏注意一點,組件要先註冊再使用,也就是說:
Vue.component('mine',{
template:'#mineTpl',
props:['name','title','city','content']
});前端
var v=new Vue({
el:'#vueInstance',
data:{
name:'zhang',
title:'this is title',
city:'Beijing',
content:'these are some desc about Blog'
}
});
若是反過來會報錯,由於反過來表明先使用了組件的,可是組件卻沒註冊。
webpack報錯後,使用webpack --display-error-details能夠排錯vue
如何讓css只在當前組件中起做用
在每個vue組件中均可以定義各自的css,js,若是但願組件內寫的css只對當前組件起做用,只須要在style中寫入scoped,即:
<style scoped></style>java
vuejs循環插入圖片
在寫循環的時候,寫入以下代碼:
<div class="bio-slide" v-for="item in items">
< img src="{{item.image}}">
</div>
此時在控制檯會出現警告
[Vue Warn]: src="{{item.image}}": interpolation in "src" attribute will cause a 404 request. Use v-bind:src instead.這裏意思是在「src」屬性插值將致使404請求。使用v-bind:src代替。
因此替換成以下:
<div class="bio-slide" v-for="item in items">
< img v-bind:src="item.image">
</div>
這裏須要主要,v-bind在寫的時候不能再用{{}},根據官方的說法:
<a v-bind:href="url"></ a>
這裏 href 是參數,它告訴 v-bind 指令將元素的 href 特性跟表達式 url 的值綁定。可能你已注意到能夠用特性插值href="{{url}}" 得到一樣的結果:這樣沒錯,而且實際上在內部特性插值會轉爲 v-bind 綁定。node
綁定value到Vue實例的一個動態屬性上
對於單選按鈕,勾選框及選擇框選項,v-model綁定的value一般是靜態字符串(對於勾選框是邏輯值):
<!-- `toggle` 爲 true 或 false -->
<input type="checkbox" v-model="toggle">
可是有時候想綁定value到vue實例的一個動態屬性上,這時能夠用v-bind實現,而且這個屬性的值能夠不是字符串。例如綁定Checkbox的value到vue實例的一個動態屬性:
<input
type="checkbox"
v-model="toggle"
v-bind:true-value="a"
v-bind:false-value="b">
<p>{{toggle}}</p >
這裏綁定後,並非說就能夠點擊後由true,false的切換變爲a,b的切換,由於這裏定義的動態a,b是scope上的a,b,並不能直接顯示出來,此時
//當選中時
vm.toggle === vm.a
//當沒選中時
vm.toggle === vm.b
因此此時須要在data中定義a,b,即:
new Vue({
el:'...',
data:{
a:'a',
b:'b'
}
});linux
實現多個根據不一樣條件顯示不一樣文字的方法
v-if,v-else能夠實現條件選擇,可是若是是多個連續的條件選擇,則須要用到計算屬性computed。例如實現當輸入框中什麼都沒寫的時候顯示字符串‘empty’,不然顯示輸入框中的內容,代碼以下:
<div id="test">
<input type="text" v-model="inputValue">
<h1>{{changeVaule}}</h1>
</div>
new Vue({
el:'#test',
data:{
changeVaule:'123'
},
computed :{
changeVaule:function(){
if(this.inputValue!==''){
return this.inputValue;
}else{
return 'empty';
}
}
}
});webpack
Vuejs在變化檢測問題
1.檢測數組
因爲javascript的限制,vuejs不能檢測到下面數組的變化:
直接索引設置元素,如vm.item[0]={};
修改數據的長度,如vm.item.length。
爲了解決問題1,Vuejs擴展了觀察數組,爲它添加一個$set()方法:
// 與 `example1.items[0] = ...` 相同,可是能觸發視圖更新
example1.items.$set(0, { childMsg: 'Changed!'})
問題2,須要一個空數組替換items。
除了$set(),vuejs也爲觀察數組添加了$remove()方法,用於從目標數組中查找並刪除元素,在內部調用了splice()。所以,沒必要:
var index = this.items.indexOf(item)
if (index !== -1) {
this.items.splice(index, 1)
}
只需:
this.items.$remove(item);
2.檢測對象
受ES5的顯示,Vuejs不能檢測到對象屬性的添加或刪除。由於Vuejs在初始化時候將屬性轉化爲getter/setter,因此屬性必須在data對象才能讓Vuejs轉換它,才能讓它是響應的,例如:
var data = { a: 1 }
var vm = new Vue({
data: data
})
// `vm.a` 和 `data.a` 如今是響應的
vm.b = 2
// `vm.b` 不是響應的
data.b = 2
// `data.b` 不是響應的
不過,有辦法在實例建立以後添加屬性而且讓它是響應的。對於Vue實例,可使用$set(key,value)實例方法:
vm.$set('b', 2)
// `vm.b` 和 `data.b` 如今是響應的
對於普通數據對象,可使用全局方法Vue.set(object, key, value):
Vue.set(data, 'c', 3)
// `vm.c` 和 `data.c` 如今是響應的
有時你想向已有對象上添加一些屬性,例如使用 Object.assign() 或 _.extend() 添加屬性。可是,添加到對象上的新屬性不會觸發更新。這時能夠建立一個新的對象,包含原對象的屬性和新的屬性:
// 不使用 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
關於vuejs頁面閃爍{{message}}
在vuejs指令中有v-cloak,這個指令保持在元素上直到關聯實例結束編譯。和CSS規則如[v-cloak]{display:none}一塊兒用時,這個指令能夠隱藏未編譯的Mustache標籤直到實例準備完畢。用法以下:
[v-cloak]{
display:none;
}
<div v-cloak>{{message}}</div>
這樣<div>不會顯示,直到編譯結束
關於在v-for循環時候v-model的使用
有時候須要循環生成input,用v-model綁定後,利用vuejs操做它,此時咱們能夠在v-model中寫一個數組selected[$index],這樣就能夠給不一樣的input綁定不一樣的v-model,從而分別操做他們。這個我在demo中的dataBind.vue中用到。
vuejs中過渡動畫
在vuejs中,css定義動畫:
.zoom-transition{
width:60%;
height:auto;
position: absolute;
left:50%;
top:50%;
transform: translate(-50%,-50%);
-webkit-transition: all .3s ease;
transition: all .3s ease;
}
.zoom-enter, .zoom-leave{
width:150px;
height:auto;
position: absolute;
left:20px;
top:20px;
transform: translate(0,0);
}
其中動畫在定的時候要注意上下對應,上面有什麼,下面有什麼,都要變化的,若是有不變化的,應該抽離出去,做爲公共css樣式,在上面的css中,若是我只寫 transform: translate(-50%,-50%);而不寫下面的transform: translate(0,0);則會致使上面的transform: translate(-50%,-50%);被添加到下面,認爲這個是不變的。
關於vuejs中使用事件名
在vuejs中,咱們常常要綁定一些事件,有時候給DOM元素綁定,有時候給組件綁定。綁定事件在HTML中用v-on:click-"event",這時evet的名字不要出現大寫,由於在1.x中不區分大小寫,因此若是咱們在HTML寫v-on:click="myEvent"而在js中寫myEvent就出錯誤,因此在vuejs的1.x綁定事件時候,要儘可能避免使用大寫字母。在2.0中沒有該限制!
v-if與v-show的區別
v-if直接不渲染這個DOM元素,而v-show是會渲染DOM元素,只是使用display:none隱藏,打開開發者工具能夠看到該DOM
關於transition全局鉤子如何在組件中使用
Vue.transition是定義一個全局transition鉤子的,若是想針對組件定義,則須要以下寫法:
export default{
transition:{
'fade':{
enter() {},
leave() {}
}
}
}
這樣fade這個過分鉤子只會做用於組件內,若是同時有同名的全局鉤子,則會優先使用組建定義的
利用vue-router如何實現組件在渲染出來前執行某個事件
export default{
data(){
return{
selected:0,
currentView:'view_0'
}
},
methods:{
choose(index) {
this.selected=index;
this.currentView='view_'+index;
}
},
route:{
data() {
/*每次切換路由,在渲染出頁面前都會執行*/
}
}
}
Vue運行報錯-。
[Vue-warn]: Missing required prop: "to" (found in component <router-link>) //報錯1
這個錯誤是<router-link>少了個to或者是寫錯
解決: 正確寫法爲:<router-link to="/home">
路由在作字符串拼接的時候,to要做爲一個屬性綁定 <router-link :to="'/home/'+item.id">
-。 聲明click/on-click的方法找不到
報錯
[Vue warn]: Invalid handler for event "on-click": got undefined //報錯1
解決: click/on-click的方法 沒有寫到methods:{ }裏面。
給組件內的原生控件添加事件,不生效的問題
<!--好比用了第三方框架,或者一些封裝的內置組件; 而後想綁定事件-->
<!--// 錯誤例子01-->
<el-input placeholder="請輸入特定消費金額 " @mouseover="test()"></el-input>
<!--// 錯誤例子02-->
<router-link :to="item.menuUrl" @click="toggleName=''">
<i :class="['fzicon',item.menuIcon]"></i>
<span>{{item.menuName}}</span>
</router-link>
<!--上面的兩個例子都無法觸發事件!!!-->
<!--究其緣由,少了一個修飾符 .native-->
<router-link :to="item.menuUrl" @click.native="toggleName=''">
<i :class="['fzicon',item.menuIcon]"></i>
<span>{{item.menuName}}</span>
</router-link>
<!--明明官方文檔有的,一堆人不肯意去看,,Fuck-->
<!--https://cn.vuejs.org/v2/guide/components.html#給組件綁定原生事件-->1234567891011121314151617181920
-。
在函數內用了this.xxx=,爲何拋出 Cannot set property 'xxx' of undefined;
這是this的套路了..this是和當前運行的上下文綁定的…
通常你在axios或者其餘 promise , 或者setInterval 這些默認都是指向最外層的全局鉤子.
簡單點說:」最外層的上下文就是 window,vue內則是 Vue 對象而不是實例!」;
解決:
暫存法: 函數內先緩存 this , let that = this;(let是 es6, es5用 var)
箭頭函數: 會強行關聯當前運行區域爲 this 的上下文;
關於this的知識, 推薦讀閱 <<你不知道的 JS 系列>>
兼容問題
使用了 axios, IE 整個家族都不支持 promise,
解決方案:
npm install es6-promise
// 在 main.js 引入便可
require("es6-promise").polyfill(); // ES6的polyfill
終於作完了第一個vue項目,本項目前端採用Vue,後端採用express+mongodb,Vue是使用vue-cli生成的項目。
開發期的問題以下:
(1)最好使用cnpm代替npm安裝依賴,由於開發過程當中少部分包若是用npm是沒法下載完成,一直卡住,換爲cnpm毫無壓力記得加上--save選項,不然別人安裝的話會缺乏包,linux下記得配置軟鏈接才能使用cnpm命令
(2)express如何設置favicon: 其實默認express已經引入了serve-favicon包,只須要使用app.use(favicon(__dirname+你的favicon路徑))便可
(3)百度地圖的引入須要異步加載,不然會報錯找不到BMap,具體見代碼
(4)非父子組件通訊新建一個Vue實例做爲通訊中轉站,能夠很方便的處理大部分非父子通訊邏輯
(5)引入reset.css是在main.js中引入
(6)es6的import規則:若是路徑最終是一個文件夾,則會首先觀察文件夾下是否有 package.json ,若是有 package.json 則會去加載 main 字段指向的文件,若是沒有 package.json ,則會在這個文件夾下尋找 index 文件並加載。因此main.js裏面加載router直接這樣寫 import router from './router'
(7)爲了處理某些瀏覽器兼容,好比ie,safari,必須引入babel-polyfill才行,在main.js里加上import 'babel-polyfill',不然ie和safari會不認識es6的語法
(8)main.js裏面Vue實例的template:"<App/>"的意思是將app組件替換掉#app的那個div,同時App也是一個組件,在components裏面必需要聲明
(9)vuex狀態管理器的使用最好按照官網那一套來寫,比較規範
(10)前端路由驗證登陸狀況能夠在路由里加上meta參數,以下圖,而後router.beforeEach裏判斷requireAuth是否爲真
(11)組件裏面data使用圖片路徑是要用require('./../mm.png')才能正確訪問圖片,這樣纔可以被webpack正確解析
(12)下拉框最好不用原生的,不一樣瀏覽器表現不一樣,得本身寫一套才行
(13)server端express自帶前端部分,在views裏面,注意設置engine解析,是html的引擎,引入ejs包
app.set('views', path.join(__dirname, 'views'));
app.engine('.html',ejs.__express);
app.set('view engine', 'html');
(14)開發環境下個人項目路徑下有中文,結果jieba分詞包執行的時候報錯:找不到jieba.node,而後將路徑改成英文問題解決,得出結論路徑別加中文,指不定啥問題會出現
部署服務器出現的問題:
(1)首先express默認設置的是3000端口,因此多個項目部署的話得修改bin/www裏面的port值,改成不同的
(2)線上部署首先得把server文件夾內的所用內容拷貝到阿里雲服務器上,新建一個文件夾來存放。阿里雲服務器必須得設置安全組,目的是將開放訪問的端口,不然端口沒法訪問,好比express設置了4000端口,阿里雲這裏就得設置4000端口開放
(3)服務器環境搭建:首先安裝node,而後安裝mongodb,注意服務器上的mongodb必須設置訪問權限,不然很是不安全,同時server端鏈接mongo的語句也得加上用戶名和密碼
(4)代碼拷貝後執行cnpm install 安裝依賴,安裝完成node www啓動項目,此時遇到問題以下圖,能夠看出此時的node不支持async函數,也就是說node版本過低了,可是我本地測試沒問題,查詢node版本後發現,本地node是v8.3.0,服務器上是v6.4,所以要升級node,具體方法爲:1,安裝n模塊 npm install -g n,這個模塊專門管理node版本的,2,n stable此命令可升級到最新穩定版,n v8.3.0這個命令可升級到指定版本。我將服務器上的node升級到和本地同樣後問題解決了
(5)因爲本項目使用了selenium-webdriver自動化測試工具當作爬蟲(緣由是某些網站主內容在iframe內,通常爬蟲沒法獲取內容,selenium內有switchToFrame方法切換frame從而獲取到內容),本地測試時這個工具運行時會自動打開chrome(事先設置了chrome參數),可是放到阿里雲服務器上時報錯找不到chrome binary,查詢後發現必須安裝chrome瀏覽器,具體連接http://www.linuxidc.com/Linux/2016-05/131096.htm 而後繼續啓動發現仍然報錯:chrome failed to start. 仔細分析後發現這是因爲沒有設置headless參數致使的,因爲阿里雲服務器沒有界面,必須設置啓動方式爲headless無頭,同時記得添加參數no-sandbox,不添加則chrome仍然沒法啓動,如下代碼在官網上在找到的。
(6)前端打包後將dist內的文件拷貝到server裏面views目錄下便可,而後啓動express便可訪問頁面,可是頁面裏面出現許多png not found,檢查後發現是路徑問題,這些找不到的png的路徑都是寫在css裏面,因爲打包後路徑發生改變,因此找不到。解決方法是修改前端build/util.js 裏面的路徑,添加publicPath參數
未解決的問題以下:
(1)開發環境下訪問第三方網站必須作跨域處理,爲啥生產環境下能夠不用跨域?直接這樣寫就行
(2)
vue 項目搭建
前言
基於Vue.js 2.x系列 + Element UI 的組件化開發方案,vue.js不支持IE8及其如下版本,由於 Vue.js 使用了 IE8 不能模擬的 ECMAScript 5 特性。 Vue.js 支持全部兼容 ECMAScript 5 的瀏覽器。vue的安裝依賴於node.js,要確保你的計算機上已安裝過node.js。可進入cmd編輯器,輸入命令 node -v進行查看。node儘可能要用新一些的版本,不然後續安裝會提示node版本太低。去node官網下個新版的node從新安裝就能夠。
安裝步驟
1.全局安裝node.js
下載地址:https://nodejs.org/en/download/
安裝成功後可進入cmd編輯器,輸入命令 node -v進行查看,出現版本號說明安裝成功,npm是包管理工具,noed安裝好就有npm指令了
C:\Users\user>node -v
v8.4.0
C:\Users\user>
2.全局安裝webpack 和 vue-cli
npm install -g webpack
npm install -g vue-cli
3.根據vue-cli構建項目
vue init webpack my-vue //建立一個項目,名稱my-vue1
cd my-vue // cd 到my-vue的根目錄下1
npm install // 下載項目依賴1
npm run dev // 讓該項目在本地上跑起來1
這樣一個基礎的vue項目目錄就自動會展示在你面前,咱們能夠來看一下其自動生成的基礎文件:
項目結構簡單介紹
├── build // 是一些webpack的文件,配置參數什麼的,通常不用動
│ ├── build.js
│ ├── check-versions.js
│ ├── dev-client.js
│ ├── dev-server.js
│ ├── utils.js
│ ├── vue-loader.conf.js
│ ├── webpack.base.conf.js
│ ├── webpack.dev.conf.js
│ └── webpack.prod.conf.js
├── config // 環境配置文件,是vue項目的基本配置文件
│ ├── dev.env.js
│ ├── index.js
│ └── prod.env.js
├── node_modules // npm包文件 是項目中安裝的依賴模塊
├── src // 源碼文件夾,基本上文件都應該放在這裏。
│ ├── assets //資源文件夾,裏面放一些靜態資源
│ │ └── logo.png
│ ├── components //這裏放的都是各個組件文件
│ │ └── Hello.vue
│ ├── router
│ │ └── index.js
│ ├── App.vue //App.vue組件
│ └── main.js //入口文件
├── static //生成好的文件會放在這個目錄下。
├── .babelrc // babel配置文件 , vue開發須要babel編譯
├── .gitignore // gitignore忽略文件
├── .editorconfig // 編碼風格配置文件
├── .postcssrc.js // postcss配置文件
├── package.json // node包管理文件
├── index.html // 首頁模板
├── package.json // 包管理文件
└── README.md // 描述文件123456789101112131415161718192021222324252627282930313233
main.js文件介紹
這裏是入口文件,能夠引入一些插件或靜態資源,固然引入以前要先安裝了該插件,在package.json文件中有記錄。
/*引入Vue框架*/
import Vue from ‘vue’
/*引入資源請求插件*/
import VueResource from ‘vue-resource’
/*重置樣式*/
import 「assets/css/base.css」
/*基本JS*/
import 「assets/js/common.js」
/*引入路由設置*/
import 「./routers.js」
/*使用VueResource插件*/
Vue.use(VueResource)
App.vue
這是一個標準的vue組件,包含三個部分,一個是模板,一個是script,一個是樣式,這裏須要瞭解vue的基礎。
import Hello from './components/Hello'
export default {
name: 'app',
components: {
Hello
}
}
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;
}
vue-route
做用:
經過管理url實現url和組件的對應,
經過url進行組件之間的切換
必須引入router組件 是單獨文件
Hello App!
Go to Foo
Go to Bar
axios使用
## 安裝 ##
npm install axios vue-axios -D
在main.js 入口文件裏面寫
import Axios from ‘axios’
import VueAxios from ‘vue-axios’
Vue.use(VueAxios,Axios)
在其它組件裏面調用
Javascript
export default {
name: 'blog',
created () {
this.getGoods()
},
methods: {
getGoods () {
this.$http.get('http://lc.shudong.wang/api_goods.php')
.then((res) => {
console.log(res.data)
})
.catch((error) => {
console.log(error)
})
}
}
}
## vue UI組件
使用目的:
提升開發效率
直接拿過來用
elementUi
安裝
npm ielement-ui -D
## 引入 main.js 入口文件 ##
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-default/index.css'
Vue.use(ElementUI)
hipv2頭痛的問題
一、先操做element分頁,切換到第2頁
模擬畫面數據從新查詢,從代碼裏面將current-page強制設置爲1(即從新查詢數據,並將當前頁重置爲第1頁)
此時畫面顯示是對的,分頁組件已經將第1頁的頁碼數字激活了
而後點擊第2頁數字,進行換頁
畫面顯示也是對的,第2頁數字變成激活狀態,可是此時居然沒法觸發current-change事件
我的猜想,其內部邏輯也許還認爲當前頁是第2頁,因此沒有再次觸發current-change
這樣會致使數據從新加載後,分頁出現bug,沒法加載分頁數據
解決分頁BUG的辦法
一、使用v-if強制刷新組件便可組件聲明改爲:(data裏面初始化paginationShow爲true)
<el-pagination
v-if="paginationShow"
:current-page.sync ="currentPage"
background @current-change="pageChange"
:page-size="perPage"
layout="total, prev, pager, next"
:total="total">
</el-pagination>
二、把search方法改爲下面這樣:
search () {
this.paginationShow = false
// 模擬ajax查詢數據處理,查詢成功後執行下面代碼
this.total = res.data.total;
this.perPage = res.data.pageSize;
this.$nextTick(function () {
this.paginationShow = true
})
}
三、注意事項:
paginationShow = true,從新顯示分頁,必須放到$nextTick,畫面刷新完畢後,否則無效果1234567891011121314151617181920212223242526272829
後期項目優化
第一次使用vue2.0開發,在使用vue-cli腳手架打包後(UI用的Element-ui)(請求模塊用的時axios),發現vendor文件很大,2M左右。。後來翻閱資料才明白,原來webpack把全部的庫都打包到了一塊兒,致使文件很大。
個人優化方法:
方法1:
1.把不常改變的庫放到index.html中,經過cdn引入,好比下面這樣:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- <meta base="/MBSS/"> -->
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta http-equiv="Access-Control-Allow-Origin" content="*" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="shortcut icon " type="images/x-icon" href="/static/img/bitbug_favicon.ico">
<!-- <link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css"> -->
<title>和佳醫院信息集成平臺</title>
<!-- 先引入 Vue -->
<!--開發環境-->
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script>
<!--生產環境-->
<!--<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>-->
<!-- 引入組件庫 -->
<script src="https://cdn.bootcss.com/axios/0.15.3/axios.min.js"></script>
<script src="https://cdn.bootcss.com/element-ui/2.3.3/index.js"></script>
<script src="https://cdn.bootcss.com/echarts/4.0.4/echarts-en.common.js"></script>
<script src="./static/js/config.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>12345678910111213141516171819202122232425262728
2.而後找到build/webpack.base.conf.js文件,在 module.exports = { } 中添加如下代碼:
externals:{
'vue': 'Vue',
'element-ui': 'ELEMENT',
'echarts':'echarts',
'axios':'axios'
}123456
3.在mian.js中import … from …就能夠去掉了,若沒去掉webpack仍是會把對應的依賴進行打包。
這樣webpack就不會把vue.js, echarts, element-ui, axios庫打包了。聲明一下,我把main.js中對element的引入刪掉了,否則我發現打包後的app.css仍是會把element的css打包進去,刪掉後就沒了。
而後你打包就會發現vendor文件小了不少~
若是你還不知足,請接着往下看·····
方法2:
vue路由的懶加載(具體做用,官網查看,這裏就很少介紹了)。
剛開始咱們使用路由多是下面這樣(router.js),這樣一開始進入頁面就會把全部的路由資源都加載,若是項目大,加載的內容就會不少,等待的時間頁就會越長,致使給用戶的很差的體驗效果。
import login from '../components/login/login.vue'
import Index from '../components/stystemm/index/index.vue'
import home from '../components/stystemm/home/home.vue'
import ImageList from "../components/stystemm/ImageList/ImageList.vue"
export default new Router({
routes:[
{
path:'/',
component: hospital
},
{path:'',component:home},
{path:'/imageList',component:ImageList}
}
]
})12345678910111213141516
爲了把路由分模塊,而後每次進入一個新頁面才加載該頁面所須要的資源(也就是異步加載路由),咱們能夠像下面這樣使用(router.js):
1.vue異步組件寫法:
export default new Router({
routes: [{
path: '/',
name: 'Login',
component: resolve => require(['../components/page/Login.vue'],resolve) ,
},
{
path: '/empi',
name: 'eMPI管理',
component: resolve => require(['../components/common/index.vue'],resolve),
children: [{
path: '/empi/summary',
name: '索引總覽',
component: resolve => require(['../components/page/eMPI/pandect/pandect.vue'],resolve)// empi - 總覽
},
{
path: '/empi/patient',
name: '患者信息',
component: resolve => require(['../components/page/eMPI/PatientInformation/PatientInformation.vue'],resolve)
}
]
},
{
path: '/role',
name: '404',
component:resolve => require(['../components/page/404.vue'],resolve)
}
]
});
123456789101112131415161718192021222324252627282930
2.es提案的import()寫法:
// 下面2行代碼,沒有指定webpackChunkName,每一個組件打包成一個js文件。
/* const Home = () => import('@/components/home')
const Index = () => import('@/components/index')
const About = () => import('@/components/about') */
// 下面2行代碼,指定了相同的webpackChunkName,會合並打包成一個js文件。 把組件按組分塊
const Home = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/home')
const Index = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/index')
const About = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/about')
{
path: '/about',
component: About
}, {
path: '/index',
component: Index
}, {
path: '/home',
component: Home
}12345678910111213141516171819
3.webpack提供的require.ensure() vue-router配置路由,使用webpack的require.ensure技術,也能夠實現按需加載。這種狀況下,多個路由指定相同的chunkName,會合並打包成一個js文件。
{
path: '/home',
name: 'home',
component: r => require.ensure([], () => r(require('@/components/home')), 'demo')
}, {
path: '/index',
name: 'Index',
component: r => require.ensure([], () => r(require('@/components/index')), 'demo')
}, {
path: '/about',
name: 'about',
component: r => require.ensure([], () => r(require('@/components/about')), 'demo-01')
}12345678910111213
方法3:
在項目config/index.js中能夠開啓gzip壓縮,對打包優化也有很大的幫助
1.首先安裝插件 compression-webpack-plugin
cnpm install --save-dev compression-webpack-plugin1
2.設置productionGzip: true
// Gzip off by default as many popular static hosts such as
// Surge or Netlify already gzip all static assets for you.
// Before setting to `true`, make sure to:
// npm install --save-dev compression-webpack-plugin
productionGzip: true,
productionGzipExtensions: ['js', 'css'],
// Run the build command with an extra argument to
// View the bundle analyzer report after build finishes:
// `npm run build --report`
// Set to `true` or `false` to always turn it on or off
bundleAnalyzerReport: process.env.npm_config_report123456789101112
3.npm run build執行後會發現每一個js和css文件會壓縮一個gz後綴的文件夾,瀏覽器若是支持g-zip 會自動查找有沒有gz文件 找到了就加載gz而後本地解壓 執行。
---------------------
首頁頭部欄的搜索功能,全局搜索。
直接跳轉查詢界面,而後這個很簡單,輸入框回車事件push到查詢界面,而後將值一起帶過去,初始化查詢界面。
但是問題來了,如今查詢這個組件裏繼續輸入而後回車。這時候路由是沒變化的,組件裏的鉤子也不會再次執行。怎麼監測到搜索內容變化呢。
首先想到的是監測路由數據變化,後來發現太low,
再次想到的是監測vuex數據,搞了半天仍是不行。
最後使用了非父子組件傳值,
創建一個bus文件,文件建一個bus.js
內容就是引入vue,創建一個空的vue實例。
在頭部搜索欄的組件裏引入bus,用bus.$emit()觸發一個事件傳值,也就是搜索框的回車時觸發。在查詢界面引入bus,以後bus.$on()獲得數據變化。而後作出相應的操做。
這裏要注意必定不能使用bus.$(‘value',function(val){});由於這樣的話,你的函數裏的this會指向空實例bus。因此咱們必須使用es6的寫法,val => {};這樣的話this會指向當前查詢界面的實例。
vue打印功能,window.open(url}這個東西不少bug。第一用戶體驗,用戶必須容許不然就沒法彈出,第二響應時間超過必定時間則沒法彈出。
解決方法:
跳轉一個指定界面,而後重定向。
var newWindow= window.open('')
setTimout(()=>{
newWindow.location.href = '新的url'
},3000);
軟刪除數據如何過濾
咱們的網站刪除若是是後臺數據庫已有數據是不能硬刪除的,只能修改某個字段而後標記爲刪除,叫作軟刪除。
這樣的話咱們的前端界面渲染時就須要過濾掉你剛剛刪除的數據
個人項目裏是用的table而後給了tableData | filterData
filterData:
var newData = [];
for(let key of tableData){
if(key.removed !== 1){ newData.push(key) }
return newData
}
簡單解釋:就是全局過濾器獲取原數據,而後若是某個字段是已經刪除了,也就是軟刪除改變了字段的數據,就無論他了,其餘的就生成一個新數組而後返回。
共用界面如何刷新
項目裏一個費用申報單界面是共用的,不少地方過來查看和編輯也是這個路由這個組件,只是不少input的內容是空或者是不能編輯只能看。
問題來了,你來到這個界面後查看完了忽然想我想如今編輯一個申報單,但是此時此刻你點擊路由這個組件是不會更新的,由於vue以爲你已經在這個界面了,他是不會理你的。
使用過幾個路由鉤子,什麼routerberfor……,什麼放在app.vue裏,都只能檢測到路由離開進來的變化,而沒法就在當前路由點擊當前路由的辯護。
解決方法使用watch 監測路由
//監視路由變化,而後初始化界面。
watch: {
'$route' (to, from) {
alert('路由改變了');
}
}
路由配置:
path:urlal
無論是插件仍是你本身寫的頭部菜單,都必定有一個事件監聽到你點擊當前路由。在這個事件裏咱們來處理
let val = new Date();
this.$router.push({
path: url/val
})
這樣你就能夠在你的組件裏監聽到路由變化了。而後也就能夠作出相應的操做。原理就是利用參數的變化唄,時間new出來的永遠都是不同的。
表單重置
項目中不少時候界面的數據不須要清除,可是一些操做會觸發驗證事件,而後一串紅字你不達到條件就不會消失,這時候很難受,因此就有了重置表單的驗證。
關於表單重置,我使用的是element-ui自帶的resetFields()事件。
咱們惟一要注意的是,不能再created()鉤子中使用,由於this.$refs[formname]中的ref,必定要加載完後才能找到的。不然會報錯說你resetFields()事件未定義。因此必定要在mounted()鉤子中使用。
require('!style-loader!css-loader!less-loader!./assets/css/common_m.less')
PS:在webpack中配置好了loader以後,不須要在引入文件時寫loader和文件後綴。
cssloader:
{
test: /\.css$/,
exclude: /node_modules/,
loader: "style-loader!css-loader",
},
{
test: /\.less$/,
exclud: /node_module/,
loader: "style-loader!css-loader!less-loader",
},
// <router-view></router-view>與寫的位置無關
path.join(__dirname,'..');
this.$set(this, '屬性', '值')
css scoped 僅本組件
對象能夠存圖片。使用require便可。
images: {
error: require('./toast-error.png'),
success: require('./toast-success.png'),
load: require('./toast-load.gif'),
waiting: require('./toast-hourglass.svg')
}
border。各屏幕分辨率不一樣出現的粗細問題。
公共部分。寫成組件。利用傳參改變樣式/內容。
Ajax。axios。
跨域問題的解決:1.服務器端協助配置。2.jsonp。3.devServer配置代理。
能用data數據解決的問題,不用方法解決。如取反。長度。是否空/false/true。(Vue是數據驅動而不是結構驅動)
v-bind:style src to ...
路由傳參。$route。
歷史記錄切換。router-link to/:to或者router.push()/router.replace()
#router.push(location) 導航到不一樣的 URL
// 聲明式
<router-link :to="...">
// 編程式
router.push(...)
// 字符串
router.push('home')
// 對象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: 123 }})
// 帶查詢參數,變成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
#router.replace(location) 它不會向 history 添加新記錄,而是替換掉當前的 history 記錄。
// 聲明式
<router-link :to="..." replace>
// 編程式
router.replace(...)
#router.go(n) 在 history 記錄中向前或者後退多少步,相似 window.history.go(n) 值能夠正能夠負
#綜合使用
const router = new VueRouter({
routes: [
{
path: '/user/:userId',
name: 'user',
component: User
}
]
})
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
router.push({ name: 'user', params: { userId: 123 }})
這兩種方式都會把路由導航到 /user/123 路徑。
// 命名視圖
// https://router.vuejs.org/zh-cn/essentials/named-views.html
// https://jsfiddle.net/posva/6du90epg/
// 有時候想同時(同級)展現多個視圖,而不是嵌套展現,例如建立一個佈局,有 sidebar(側導航) 和 main(主內容) 兩個視圖,這個時候命名視圖就派上用場了。
// 你能夠在界面中擁有多個單獨命名的視圖,而不是隻有一個單獨的出口。若是 router-view 沒有設置名字,那麼默認爲 default。
<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>
// 一個視圖使用一個組件渲染,所以對於同個路由,多個視圖就須要多個組件。確保正確使用 components 配置(帶上 s):
const router = new VueRouter({
routes: [
{
path: '/',
components: {
default: Foo,
a: Bar,
b: Baz
}
}
]
})
重定向 和 別名
切換時清空歷史記錄。數據丟失。sessionStorage。
相對路徑。
append。concat。
渲染成某個標籤。tag
能夠在router-link內嵌套其餘內容。
類型都是Object
$route.params(一個 key/value 對象,包含了 動態片斷 和 全匹配片斷,若是沒有路由參數,就是一個空對象。)
$route.query(一個 key/value 對象,表示 URL 查詢參數。例如,對於路徑 /foo?user=1,則有 $route.query.user == 1,若是沒有查詢參數,則是個空對象。)
<div>
<router-link :to="{ name: 'Hello' , params: { userId: 123 }}">
click1
</router-link>
</div>
<div>
<router-link :to="{ path: 'hello' , query: {show: 2}}">
click2
</router-link>
</div>
console.log(this.$route.params.userId)
console.log('top is params, bottom is query')
console.log(this.$route.query.show)
watch:
watch: {
'$route' (to, from) {
// 對路由變化做出響應...
}
}
v-show和v-if 。v-if爲假直接不渲染。v-show爲假display none。
當 v-if 與 v-for 一塊兒使用時,v-for 具備比 v-if 更高的優先級。
我的建議:外容器overflow hidden,內容器overflow scroll。
過渡效果:
<transition name="fade"></transition>
.fade-enter-active, .fade-leave-active {
-webkit-transition: opacity .7s;
transition: opacity .7s;
}
.fade-enter, .fade-leave-active {
opacity: 0
}
路由鉤子:判斷從哪一個路由過來,到哪一個路由。而後跳轉到哪一個路由。(全局鉤子。局部鉤子。)
component頁面內也能夠監聽路由。
滾動行爲。歷史記錄之間切換。頁面位置。返回對象。
scrollBehavior (to, from, savedPosition) {
return { x: 0, y: 0 }
}
錨點的實現。經過scrollTop。或滾動行爲。
路由元信息。路由嵌套。
懶加載。
在異步加載頁面中載嵌入異步加載的組件時對頁面是否會有渲染延時影響?
答:會, 異步加載的組件將會比頁面中其餘元素滯後出現, 頁面會有瞬間閃跳影響;
解決方案:由於在首次加載組件的時候會有加載時間, 出現頁面滯後, 因此須要合理的進行頁面結構設計, 避免首次出現跳閃現象;
At all:
一、路由頁面以及路由頁面中的組件全都使用懶加載
優勢:(1)最大化的實現隨用隨載
(2)團隊開發不會由於溝通問題形成資源的重複浪費
缺點:(1)當一個頁面中嵌套多個組件時將發送屢次的http請求,可能會形成網頁顯示過慢且渲染良莠不齊的問題
二、路由頁面使用懶加載, 而路由頁面中的組件按需進行懶加載, 即若是組件不大且使用不太頻繁, 直接在路由頁面中導入組件, 若是組件使用較爲頻繁使用懶加載
優勢:(1)可以減小頁面中的http請求,頁面顯示效果好
缺點:(2)須要團隊事先交流, 在框架中分別創建懶加載組件與非懶加載組件文件夾
三、路由頁面使用懶加載,在不特別影響首頁顯示延遲的狀況下,根頁面合理導入複用組件,再結合方案2
優勢:(1)合理解決首頁延遲顯示問題
(2)可以最大化的減小http請求, 且作其餘他路由界面的顯示效果最佳
缺點:(1)仍是須要團隊交流,創建合理區分各類加載方式的組件文件夾
export default new Router({
routes: [
{
path: '/',
component: resolve => require(['components/Hello.vue'], resolve)
},
{
path: '/about',
component: resolve => require(['components/About.vue'], resolve)
}
]
})
// solve:
// components/page
<keep-alive> 包裹動態組件時,會緩存不活動的組件實例,而不是銷燬它們。和 <transition> 類似,<keep-alive> 是一個抽象組件:它自身不會渲染一個 DOM 元素,也不會出如今父組件鏈中。
當組件在 <keep-alive> 內被切換,它的 activated 和 deactivated 這兩個生命週期鉤子函數將會被對應執行。
主要用於保留組件狀態或避免從新渲染。
組件:
當註冊組件(或者 props)時,可使用 kebab-case ,camelCase ,或 TitleCase 。Vue 不關心這個。
component命名要求:
1. 檢查名稱是否與 HTML 元素或者 Vue 保留標籤重名,不區分大小寫。(經常使用HTML標籤)
2. 檢查組件名稱是否以字母開頭,後面跟字母、數值或下劃線。
使用 Virtual DOM 解析模板時,不會將模板中的標籤名轉成小寫,而是保留原始標籤名。而後,使用原始的標籤名進行匹配組件。
例如, <MyComponent></MyComponent> 不會轉爲爲小寫形式,直接以 MyComponent 爲基礎開始匹配。
固然,匹配的規則依次匹配:原標籤名、camelCase化的標籤名、PascalCase化的標籤名。
computed,內容變時會更新,不然會緩存起來。
若是是傳參等方式獲得值,須要判斷值是否爲空,不然會報值爲undefined的錯。
vue項目中,不用寫CSS的兼容性代碼。
由於vue-loader在編譯.vue文件的時候,使用了Postcss的工具,它會給有兼容性問題的屬性添加兼容性代碼。
它是根據can i use官網寫的代碼。
寫在<style></style>內纔會生效。在html中添加style屬性是不會添加兼容性代碼的。
換行問題:
v-html能夠直接加<br>進行換行,v-model中無效
例外:textarea標籤使用v-model時,可使用\r進行換行
ref的使用:
在父頁面調用子組件的標籤:
在父頁面中的組件上加ref。而後在子組件中的某個標籤加ref。便可。
nextTick
將回調延遲到下次 DOM 更新循環以後執行。
https://cn.vuejs.org/v2/api/#vm-nextTick
new Vue({
// ...
methods: {
// ...
example: function () {
// 修改數據
this.message = 'changed'
// DOM 尚未更新
this.$nextTick(function () {
// DOM 如今更新了
// `this` 綁定到當前實例
this.doSomethingElse()
})
}
}
})
box-sizing: border-box
:disabled="type == '值'"
:class = name
name能夠是compute
getBoundingClientRect用於獲取某個元素相對於視窗的位置集合。集合中有top, right, bottom, left等屬性。
點擊事件。取消冒泡。
v-on:click.stop="doThis"
阻止默認事件。
v-on:click.prevent="doThis"
https://cn.vuejs.org/v2/guide/events.html#事件修飾符
組件內部的方法,命名建議以兩個下劃線開頭
外部傳參方法等,不用兩個下劃線開頭。
padding取%值,
> %,規定基於父元素的寬度的百分比的內邊距。
給按鈕加padding。方便點擊
或者整個部分能夠點擊。
export 和 export default
http://es6.ruanyifeng.com/#docs/module#export-命令
http://es6.ruanyifeng.com/#docs/module#export-default-命令
切換組件時,但願保留組件的狀態時,加上keep-alive 便可
我的作vue項目的心得和體會
vue.js
首先,vue.js是一個數據驅動視圖的一個js框架,操做數據,而後實時反應到dom元素上的一個動態視圖框架,它也是一個漸進式開發框架,好比,我用vue-cli搭建了一個本地開發環境,用nodejs跑了起來,當把vue引進來以後,要作項目仍是遠遠不夠的,就用到了vue全家桶
好比
UI框架 : element-ui
http請求工具:axios(我的推薦用這個)
cookie工具:vue-cookie
構建工具:vue-cli
路由插件:vue-router
狀態管理工具:vuex
滾動條插件:vuescroll
兼容IE的插件:babel-polyfill(固然vue只兼容到IE9+)
若是平時項目中你用到了哪些框架及插件,就能夠經過npm install,下載下來,引入到項目中去就ok了
我的以爲項目目錄結構能夠是這個樣子的
主要是src文件夾,assets主要用於放一些項目中的圖片等之類的,compoents就放一些本身定義的組件,pages就放頁面,固然都是vue文件啦,router放路由配置,server放一些靜態目錄什麼的,放一些常量什麼的均可以,store,熟悉vuex的小夥伴應該都知道,沒錯,就是放vuex的
經過用vue作了一些東西后,引起了個人一些思考,也算是心得吧,跟我寫代碼的風格有關係,也許你以爲我說的這些很差,你能夠繼續延用你的風格,哈哈,畢竟敲代碼都有本身獨特的風格嘛,哪一個程序猿尚未點傲嬌的小脾氣呢!
關於使用UI框架
通常我都是用element-ui這個ui框架,其中有一些ui組件特別好用,好比$message,提示組件,不用本身寫,直接調用,就能用於增長,修改的一些功能,好比提示新增成功,修改爲功等,還有按鈕組件,彈出框組件等一些基本的組件,對於我本身寫的其餘代碼後續幾乎沒有衝突,且靈活度高的,我就直接用了框架內的組件,可是一些可控性不強,且不夠靈活,幾乎不能改動的組件我就會選擇本身寫,好比樹形控件,這個樹形控件的樣式特別單一,並且不可控,並且靈活度不高,我不是很喜歡,就利用vue的遞歸組件本身寫樹形控件,感興趣的小夥伴能夠看下我下篇博客,立刻就發《vue如何用遞歸組件寫樹形控件》,總結一句話,靈活度高,就用框架,靈活度不高,就本身寫,本身寫的可控性很強!
關於封裝組件
有時候項目中常常會碰到這種狀況,好幾個頁面的列表頁除了表頭不同,幾乎樣式是如出一轍的,這樣的你就能夠封裝一個列表組件了,可是隻適用於樣式差很少的列表,若是你以爲都封裝進一個組件裏面,對後續開發的一些可控性不是很強,並且每一個頁面的需求都不同,處理方式和方法都不很同樣,那麼我勸你仍是老老實實本身寫列表吧,由於你封裝到一個組件中,對於每一個頁面的處理方式都要進行判斷,這樣會顯得這個組件很臃腫,我以爲還不如分開寫,因此是否要把一個功能模塊封裝進組件,靈活把握就能夠了
關於一些目錄和http請求
關於一些目錄,好比導航目錄,通常是寫死的,固然也有從後臺獲取的,我如今這個項目就是從後臺獲取目錄,還有請求URL,和一些http請求,你就能夠新建一個server目錄,而後分模塊的寫道js文件夾裏面,return出去,而後再在其餘頁面中引入,這樣作的好處是,模塊化管理,將常量和http請求進行統一管理,好比下圖
我就把http請求進行了統一管理,而後暴露出去,未來有改動我就能夠直接改這裏就能夠了
關於vuex
下面說一說vuex,也許有許多小夥伴對於這個都不知道幹嗎用的,根據個人理解,vuex並非那麼神祕,就是一個公共狀態庫,是互不聯繫的兩個組件的通訊橋樑,好比我又一個列表組件1,又有一個列表組件2。這兩個組件徹底不同,絲毫沒有聯繫的那種,可是它們之間須要通訊,好比都須要根據一個布爾值show來進行顯示仍是隱藏,這樣就能夠把這個show放進vuex狀態庫裏面,當這個show改變的時候,這兩個列表組件就能夠根據show的變化自動的進行顯示隱藏了
關於http請求寫在哪裏的問題
我一開始接觸vuex的時候,vuex裏面有一個actions,既能夠進行同步操做,又能夠進行異步操做,官網上是推薦將http異步請求放在actions裏面,由於當時剛學,沒有判斷能力,就按照官網上來寫,在vue文件裏面只寫邏輯代碼,而把全部的http異步請求所有寫在了actions裏面,這樣問題就來了,首先mutations裏面的函數必需要用它來提交,並且vue裏面經過引入import { mapGetters , mapActions} from 'vuex',來獲取到函數和狀態,我發現寫一個http須要寫好多代碼,我若是直接寫道methods裏面,就特別簡單,後來我就在想到底放哪裏簡單些,綜合了網上的一些見解,我以爲這跟我的代碼風格有關係,官網是推薦寫到actions裏面,但是若是一個頁面裏面的一些http請求只是本身用,也不跟其餘頁面以及組件進行通訊的話,我以爲沒有必要寫到vuex裏面,寫在methods裏面反而簡單些,反正到最後項目的數據都能流通就能夠了,我以爲一些http請求獲得的數據要和其餘組件或頁面共用的話,我以爲必需要放在vuex裏面,這是最棒的辦法,若是是本身在本身的小窩裏小打小鬧,也不影響別人,那麼咱們仍是寫在methods裏面吧,畢竟別人又不用,爲何要把它驅逐家門呢,哈哈!!
就說到這裏吧
Vue項目經驗
動態添加class或style
有時候但願根據某個狀態值來決定是否添加某個類,能夠這樣:
// 數組語法
<div :class="['a',value==true?'b':'']"> //類a老是存在,當value爲真時類b存在
// 對象語法
<div :class="{'a':true,'b':value}"> //類a,b都由value控制
<div :style="{background:'url('+value.url+')'}"> //對於style,最好用對象語法,屬性值取自當前vue實例
<div className={style.root} style={{ background: `url(${graduateCelebrate}) center center/ 100% 100% no-repeat content-box` }}>
綁定事件函數
有兩種方式:
// 方式1
<div @click='handle'></div> //handle函數的this指向當前vue實例,而且會將event對象傳入handle做第一個參數,一般可用event.target獲取被點擊的DOM元素
// 方式2
<div @click='handle("param1",$event)'></div> //handle函數的this指向當前實例,也可將$event傳入handle,做用同上,通常用來獲取被點擊的DOM元素
關於箭頭函數
vue的一些配置項,如mounted,beforeRouteEnter,beforeRouteLeave等,自己是一個函數,若使用箭頭函數語法,則其內的this對象不是當前vue實例。所以這三個配置項不要用箭頭函數,其它的配置項,如methods,computed,watch等接受對象做爲配置的,其內的函數最好用箭頭函數,另外setTimeout(fn,time)中的fn最好也用箭頭函數。
watch對象變化:
'messages': { // messages是一個數組,監聽數組或對象的變化
handler: function(newValue, old) {
if (newValue.length == 0) {
setTimeout(() => {
history.back();
}, 1000)
}
},
deep: true
}
關於beforeRouteEnter和beforeRouteLeave
beforeRouteEnter(to,from,next) 沒法訪問當前vue實例,通常用於從localStorage中讀取數據恢復頁面,好比從頁面a到b,在從b回到a,若a有數據變化(ajax拉取)就更新頁面,不然不更新;或者還原當前滾動條位置
beforeRouteLeave(to,from,next) 可訪問當前vue實例,通常用於頁面離開時將某些狀態保存在localStorage中,例如當前滾動條位置
兩者都必須顯示調用next函數
keep-alive和router-view混合使用
// 這是目前用的比較多的方式
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
...
routes: [
{ path: '/', redirect: '/index', component: Index, meta: { keepAlive: true }},
{
path: '/common',
component: TestParent,
children: [
{ path: '/test2', component: Test2, meta: { keepAlive: true } }
]
}
....
// 表示index和test2都使用keep-alive
如有三個頁面A->B->C,但願A->B時B拉新數據;C返回B時B不拉新數據,且保存B到C以前的位置,該如何作?
一、給B設置keepAlive:true;
二、在B的beforeRouteEnter中作獲取數據的操做,該鉤子的三個參數能夠判斷B的上一個頁面,從而決定是否拉數據;
在B的beforeRouteLeave裏用localStorage記錄位置,並清除和頁面展示相關的數據狀態;
三、在接口回調裏最好用EventCenter這種觀察者模式來觸發數據獲取成功的事件
四、在B的mounted鉤子裏接受數據獲取成功的事件,就能夠拿到數據
五、在B的activated鉤子裏取localStorage裏的位置
router-link經常使用方式
<!-- 命名的路由 -->
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
<!-- 帶查詢參數,下面的結果爲 /register?plan=private -->
<router-link :to="{ path: 'register', query: { plan: 'private' }}">Register</router-link>
//對應js
this.$route.params.userId
this.$route.query.plan
過分動畫
單元素過渡
transition包一個含有v-if或v-show指令的元素就行
動畫過程
多元素過渡
transition下只能有一個根元素,因此多元素時必須用v-if,v-else來保證只有一個,此外,多個相同標籤時,最好給每一個標籤設置key
多組件過渡
用動態組件便可
列表過渡
需用transition-group組件包裹,被包裹元素必須設置key,其餘和單元素同樣
數據拉取
數據獲取操做最先能夠放在每一個組件的beforeRouteEnter裏,而後利用觀察者模式把數據傳到beforeMount鉤子函數裏作邏輯操做
beforeRouteEnter(to, from, next) {
let feed_id = to.params.id;
if (from.name != 'CommentDetail' && feed_id) {
getArticleDetail({
feed_id: feed_id
}).then(res => EventCenter.$emit('renderArticle', res));
getComment({
feed_id: feed_id
}).then(res => EventCenter.$emit('renderComment', res));
}
next();
}
beforeMount(){
// 一、渲染文章詳情
EventCenter.$on('renderArticle', res => {
});
// 二、渲染文章評論
EventCenter.$on('renderComment', res => {
})
}
插件 or 組件
對於全局使用頻率較高的最好寫成插件,而不是組件。例如loading,toast之類,若寫成組件,則須要在每一個父組件中引入該組件,比較麻煩,寫成插件就能夠直接調用
import $ from 'n-zepto';
import Vue from 'vue';
export default {
install() {
var timer = null;
Vue.prototype.$alerTip = function(text, delay, options) {
var defaultCssObject = {
position: 'fixed',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
zIndex: 10000,
minWidth: '1.5rem',
margin: '0 auto',
left: 'calc((100% - 1.5rem) / 2)',
bottom: '1.4rem',
borderRadius: '.1rem',
height: '.5rem',
lineHeight: '.5rem',
background: '#000',
opacity: 0.85,
color: 'white',
};
var cssObject = options || defaultCssObject;
var temp = `<div class="v-toast">${text}</div>`;
var $div = $(temp);
$div.css(cssObject);
$('body').append($div);
clearTimeout(timer);
timer = setTimeout(() => {
$('.v-toast').remove();
timer = null;
}, delay);
}
}
}
vue父子組件生命週期執行順序問題
父子組件鉤子執行順序:
father created
father before mounted
son created
son before mount
son mounted
father mounted
因此,你在父組件 beforeMounted 中已初始化的值必定能夠經過props下發到子組件
vue-router切換頁面滾動條位置問題
注意:scrollBehavior只有在history.pushState可用時纔有效,而該方法僅兼容到IE10(移動端可放心使用)
const router = new VueRouter({
routes,
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
if (from.meta.keepAlive) { // 經過meta屬性精細控制
from.meta.savedPosition = document.body.scrollTop;
}
return { x: 0, y: to.meta.savedPosition || 0 }
}
}
})
vue庫的引入問題
vue提供衆多版本庫文件,在使用*.vue單文件組件的開發模式時,只需引入vue.runtime.min.js便可,該庫體積最小,不過要注意初始化vue實例時,不能用template選項,而應該換爲render
new Vue({
el: '#app',
router,
render: h => h(App)
})
// webpack對應修改:
alias: {
'vue$': 'vue/dist/vue.runtime.min.js'
}
vuex組件中訪問state報錯TypeError: Cannot read property ‘state’ of undefined」在組件中使用this.$store.state.test訪問state的屬性報錯,是由於store的實例並未注入到全部的子組件,需修改main.jsnew Vue({el: '#app',store, //將store注入到子組件router,components: { App },template: '<App/>'})