也可能是因為接觸vue時間也不長,經常落入不知名的‘坑’中,對於我這個菜鳥來說,每次‘落坑’無疑是一場不小的災難。前兩天有個朋友在問我,在使用
vue
中有沒有遇到一些很難解決的問題,一下我也只能說出一兩個,正所謂‘光說不練,假把式’,所以索性就抽時間總結一下我在專案中遇到的vue
的問題,也貼出了效果圖片,這樣看起來也比較清晰。有寫的不對的地方,在您時間還允許的情況下,還勞煩大家告訴我哦,我也好儘早修改,以免給看文章的其他同仁帶來不必要的麻煩!(當前版本:"vue@2.5.3") -------------------在此謝過!-----------
說到vue的實戰,不得不說vue
專案建立,那麼關於vue cli
專案搭建,我在之前的文章中有專門寫過,有不懂的同學,可參考我的第一篇文章:
vue cli 框架搭建
- 接下來給大家安利一個vue的網頁執行工具 iVuewRun網頁版的vue,可直接執行使用,還可以分享給小夥伴!
先陳列一下vue的整體架構:
事件:methods:{ };
過濾器:filters:{ };
自定義指令:directive:{ };
模版:components:{ };
計算:conputed:{ };
觀察者:watch:{ };
鉤子函式:
created:function(){
//建立
},
mounted:function(){
//掛載
},
updated:function(){
//更新
},
destoryed:function(){
// 銷燬
}
複製程式碼
一、用不同的方式新增css
。
在
vue
的每個元件中,都可以自定義css
和js
,那麼如果只希望當前的css
只在當前頁面生效,可以在style
的標籤這樣書寫,這樣當前頁面的所有css
樣式,除當前元件,不會在其他元件生效並且不會影響到其他元件頁面渲染。
<style scoped> </style>
複製程式碼
如果你引入來sass到vue專案中,那麼只需在當前元件新增lang屬性即可:
sass $
<style scoped lang="scss"> </style>
複製程式碼
亦你的專案引入的不是sass
,是less
,也是同樣更改lang
屬性即可:
less @:
<style scoped lang="less"> </style>
複製程式碼
動態傳入style
值的幾種方式:
1.正常class
樣式:
<template>
<div>
<p class="fs20">1.正常class樣式: 2018年8月27日</p>
</div>
<template>
<style>
.fs20 {
font-size: 20px
}
</style>
複製程式碼
頁面展現:
對於多個"../../../"查詢引入檔案時,可以先跳到最外層,即src層開始查詢
關於引入外部的less檔案或者img圖片:
~@/xxx/...
複製程式碼
關於引入外部js、template、component:
@/xxx/...
複製程式碼
2.根據data
中的className
對應的class
,可用於動態切換class
:
<template>
<div>
<p :class="className">2.動態切換class的值</p>
</div>
<template>
<script>
export default {
data() {
return {
className: "classA"
}
},
components: {},
mounted() {},
methods: {},
watch: {}
}
</script>
<style>
.classA {
color: yellowgreen
}
</style>
複製程式碼
頁面展示:
3.給當前的class
新增判斷:當isOk
為true
時新增class
,為false
時不新增:
<template>
<div>
<p :class="{colorRed:isOk}">
3.新增判斷:當isOk為true是新增class,為false時不新增
</p>
<Checkbox v-model="isOk">Checkbox</Checkbox>
</div>
<template>
<script>
export default {
data() {
return {
isOk: true,
}
},
components: {},
mounted() {},
methods: {},
watch: {}
}
</script>
<style>
.colorRed {
color: red
}
</style>
複製程式碼
頁面展示:
4.以陣列的方式,一次新增多個class
:
<template>
<div>
<p :class="[classC,classD]">4.以陣列的方式,一次新增多個class</p>
</div>
<template>
<script>
export default {
data() {
return {
classC: "classC",
classD: "classD"
}
},
components: {},
mounted() {},
methods: {},
watch: {}
}
</script>
<style>
.classC {
font-size: 16px;
font-weight: 600;
}
.classD {
color: blue
}
</style>
複製程式碼
頁面展示:
5.使用三元運算子判斷切換class
樣式,當isOk
為true
時用的是classA
,當為false
的時候用的是classB
:
<template>
<div>
<p :class="isOk?classA:classB">5.使用三元運算子判斷切換class樣式</p>
</div>
<template>
<script>
export default {
data() {
return {
isOk: true,
classA: "classA",
classB: "classB"
}
},
components: {},
mounted() {},
methods: {},
watch: {}
}
</script>
<style>
.classA {
color: yellowgreen
}
.classB {
color: green
}
</style>
複製程式碼
頁面展示:
6.繫結動態的style
的樣式:
<template>
<div>
<p :style="{color:color,fontSize:font}">6.繫結style的樣式</p>
</div>
<template>
<script>
export default {
data() {
return {
color: "red",
font: "18px",
}
},
components: {},
mounted() {},
methods: {},
watch: {}
}
</script>
<style>
</style>
複製程式碼
頁面展示:
7.給style
繫結物件:
<template>
<div>
<p :style="styleObject">7.給style 繫結物件</p>
</div>
<template>
<script>
export default {
data() {
return {
styleObject:{
color:"pink",
fontWeight:"600"
}
},
components: {},
mounted() {},
methods: {},
watch: {}
}
</script>
<style>
</style>
複製程式碼
頁面展現:
二、關於迴圈中的img
的src
賦值的問題
在
vue
中的迴圈是使用v-for
來實現的,在標籤中注入v-for
,在接下來使用到的地方就可以直接使用。
<template>
<div v-for="item in cityList">
<div>城市名稱:{{item.title}}</div>
<div>城市ID:{{item.id}}</div>
<div>城市圖片:<img src={{item.img}}></div> //這行是報錯的
</div>
</template>
<script>
export default:{
data(){
return:{
cityList:[{
title:'北京',
id:001,
img:'static/logo.png'
},
{
title:'上海',
id:002,
img:'static/logo.png'
}]
}
}
}
</script>
複製程式碼
報錯如下:(這裡意思是在“src”屬性插值將導致404請求。使用v-bind:src
簡寫為:src
代替)
[HMR] bundle has 1 errors
client.js?d90c:161 ./~/_vue-loader@12.2.2@vue-loader/lib/template-compiler?{"id":"data-v-60d18b79","hasScoped":true,"transformToRequire":{"video":"src","source":"src","img":"src","image":"xlink:href"}}!./~/_vue-loader@12.2.2@vue-loader/lib/selector.js?type=template&index=0!./src/components/vuetest.vue
(Emitted value instead of an instance of Error)
Error compiling template:
<div>
<h1>vue測試頁面</h1>
<div v-for="item in cityList">
<div>城市名稱:{{item.title}}</div>
<div>城市ID:{{item.id}}</div>
<div>城市圖片:<img src="https://user-gold-cdn.xitu.io/2017/11/26/15ff7324b8313b05"></div>
</div>
</div>
- src="https://user-gold-cdn.xitu.io/2017/11/26/15ff7324b8313b05": Interpolation inside attributes has been removed. Use v-bind or the colon shorthand instead. For example, instead of <div id="{{ val }}">, use <div :id="val">.
@ ./src/components/vuetest.vue 10:2-340
@ ./src/router/index.js
@ ./src/main.js
@ multi ./build/dev-client ./src/main.js
複製程式碼
因為vue官網在介紹v-bind時,不可以再使用{{}},例如href
的兩種使用:
<template>
<div>
<a :href='msg'>獲取動態資料</a>
<a href='http://www.baidu.com'>百度</a>
</div>
</template>
<script>
export default:{
data(){
return:{
msg:'http://www.baidu.com'
}
}
}
</script>
複製程式碼
正確程式碼如下:
<template>
<div v-for="item in cityList">
<div>城市名稱:{{item.title}}</div>
<div>城市ID:{{item.id}}</div>
<div>城市圖片:<img :src='item.img'></div>
</div>
</template>
<script>
export default:{
data(){
return:{
cityList:[{
title:'北京',
id:001,
img:'static/logo.png'
},
{
title:'上海',
id:002,
img:'static/logo.png'
}]
}
}
}
</script>
複製程式碼
三、關於v-if
和v-show
的區別
在vue中有兩種隱藏元素的方式,那就是
v-if
和v-show
,但是兩者有什麼區別呢?什麼時候用v-if
,什麼時候用v-show
呢?
當v-if
和v-show
兩個值都為true
時的渲染結果,都正常渲染
v-if
和v-show
的值都為假值時:頁面沒有渲染,v-if
未渲染dom
元素,v-show
渲染成功,但被新增了style
為display:none
。
四、關於在vue
中如何操作DOM
元素。
我們都知道vue框架中我們一般操作的都是資料,那麼假如我們要操作dom元素使用什麼方法呢?下面就來介紹一下!
假如有以下元素,我們要獲取這個h2元素的文字,需要給此元素新增ref屬性,並賦予名字。
<h2 ref='foo'>我是ref的值</h2>
複製程式碼
接下來就可以使用這個方法獲取到它的文字(注意是this.$refs
不是this.$ref
):
console.log(this.$refs.foo.innerHTML')
複製程式碼
那麼如何改變h2
中的文字呢?
this.$refs.foo.innerHTML='我是新值
複製程式碼
這樣就可以和以前一樣,輕鬆的操作dom元素了,但是vue還是以運算元據為核心,所以建議儘量少的使用以上方法。
五、探究router-link
中的tag
屬性。
在
vue
路由的router-link標籤中有一個屬性tag
,是我今天在查閱資料時發現的,感覺比較有意思,推薦給大家。
那麼我們就給<router-link to='/about'>
的標籤上新增上tag
屬性,並賦值:
<router-link to='/fenceCenter' >中心點</router-link>
<router-link to='/vuetest'tag='li'>vue測試</router-link>
複製程式碼
那麼我們看看它和我們正常渲染的有什麼不同
是不是很神奇呢? tag
除了可以賦值li
,還可以賦值成你想要的所有的標籤哦! p,span,h1,div
....都可以哦!快去動手試試吧!!
六、vue中的指定路由跳轉router
在我們的實際業務中,有時需要在某一元件內,點選一個按鈕或者是點選一個連結切換跳轉到其他元件,也就是跳轉路由,我們可以試試下面的方法:
//直接跳轉
this.$router.push('/map')
//條件允許時跳轉
if(this.data){
this.$router.push('/map')
}
複製程式碼
注意:
router
需要掛在到vue
例項上,這樣才可以獲取到this.$router
,而且push
後面的括號中的路由地址,也需要在vue
的router
中有註冊,最後,在('')中填寫你需要跳轉的路由即可完成跳轉。
七、vue的路由router中的go方法
上面剛剛有講到路由router
,接下來再講一個和router
相關的方法go
,這個方法是用作前進後退導航來使用的,有時實際業務需要我們新增一個返回上一頁面的功能,那麼我們就可以用go
來實現。當為‘-1’時就可以後退到上一個路由頁面。
this.$router.go('-1')
複製程式碼
八、輕鬆編寫vue元件
vue是一個單頁面應用,那麼就會涉及到元件的問題,例如
A
頁面為一個主頁面,A1,A2,A3
為3個子頁面,但A1,A2,A3
頁面的內容分別比較複雜,需要單頁面來編輯,這時我們就需要把A1,A2,A3
寫成3個元件,然後全部載入A的主頁面上;又或有這樣的情況,當子頁面的複用率比較高時,同樣可以採取使用元件的方式來實現。總之,你可以把你想實現的寫成元件,這樣第一方便修改,第二頁面乾淨整潔,第三;讓別人看起來一目瞭然。 下面我們就看看,元件到底是怎麼實現吧!!!
A頁面:
<template>
<div>
<h2 style="color:red">我是主頁面</h2>
<content><content> //我是新增的元件
</div>
</template>
<script>
import content from './content' //找到元件的位置,引入
export default {
name: "",
data() {
return {
}
},
components:{
content //將元件寫入模板內才可生效,當有多個元件,看用逗號分開
},
mounted() {
},
methods: {}
}
</script>
<style scoped>
</style>
複製程式碼
A頁面的子頁面(content元件頁面): 元件頁面就是普通頁面,當然元件頁面的事件也是會帶到主頁面的。
<template>
<div @click="foo()">我是元件頁面</div>
</template>
<script>
export default {
name: "",
data() {
return {
}
},
mounted() {
},
methods: {
foo(){
alert("我是好人")
}
}
}
</script>
<style scoped>
</style>
複製程式碼
這時我們來看一下效果:
這樣你想要的效果就有了哦!
那麼還需要注意一點:如果你的元件名字是駝峰式寫法,那麼按照以下方式修改:
<template>
<div>我是主頁面<content-f> </content-f> //這裡要這樣寫</div>
</template>
<script>
import contentF from './contentF' //找到元件的位置 引入
export default {
name: "",
data() {
return {
}
},
components:{
contentF //將元件寫入模板內才可生效,當有多個元件,看用逗號分開
},
mounted() {
},
methods: {}
}
</script>
<style scoped>
</style>
複製程式碼
九、在vue
中觀察者watch
的用法
在
vue
的官網是這麼介紹的:把它命名為 觀察者模式 雖然計算屬性在大多數情況下更合適,但有時也需要一個自定義的watcher
。這是為什麼vue
通過watch
。 選項提供一個更通用的方法,來響應資料的變化。當你想要在資料變化響應時,執行非同步操作或開銷較大的操作,這是很有用的。 通俗點講,就是在vue
中有一個watch
,它可以監聽你的資料是否發生變化,一旦發生變化,可以進行某些操作,那麼我們就來試試:
<template>
<div>
<button @click="foo()">點選按鈕</button>
<div>{{value}}</div>
</div>
</template>
<script>
export default {
name: "",
data() {
return {
value:1,
}
},
mounted() {},
watch:{
value:function(val,oldval){
console.log(val,oldval)
}
},
methods: {
foo() {
this.value=5
}
}
}
</script>
<style scoped>
</style>
複製程式碼
我們點選一下,看一下結果:當value
被改變時,會在後臺列印出當前的值和改變前的值:
但當我們再次重複上一次的動作時,並不會再次列印結果,那是因為value值改變成5後,再次點選,還是同樣的值,value的值並沒有再次發生變化。
在watch
裡面有一個deep
的引數,可以監聽object
中屬性的變化。(我們上面使用的是number
,而同樣使用上面的方法,並不能監聽到物件的屬性值的變化)
下面我們來使用deep
來檢測一下物件屬性:
<template>
<div>
<button @click="foo()">點選按鈕</button>
<div>{{value}}</div>
</div>
</template>
<script>
export default {
name: "",
data() {
return {
value:{
a:1,b:2
}
}
},
mounted() {},
watch:{
value:{
handler(val,oldVal){
console.log("lalala",val,oldVal)
} ,
deep: true,
immediate: true
}
},
methods: {
foo() {
this.value.a=5;
this.value.b=6;
}
}
}
</script>
<style scoped>
</style>
複製程式碼
十、關於assets
和 static
的區別,靜態資源到底該放哪裡?
在我們搭建好的
vue-cli
的專案中會自動給我們建兩個資料夾來存放我們的資料,圖片之類的資產,這兩個分別是assets
和static
兩個,那麼我們怎麼來區分這兩個資料夾呢?在通過直譯我們瞭解到assets
的中文意思為資產,而static
的中文意思為靜態的,靜止的;
原因如下:
assets
目錄中的檔案會被webpack
處理解析為模組依賴,只支援相對路徑形式。
static/
目錄下的檔案並不會被webpack
處理:它們會直接被複制到最終的打包目錄(預設是dist/static
)下。
下面來一段程式碼,來現身說法:
<template>
<div class="hello">
<div v-for="item in cityList" :key="item.id">
<div >{{item.title}}</div>
<div>城市圖片:<img :src="item.img"></div>
</div>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data() {
return {
cityList: [{
title: '北京',
id: "001",
img:"../assets/logo.png" //這行是不被識別的
},
{
title: '上海',
id: "002",
img: "static/logo.png" //這個可以被正確顯示
}
]
}
}
}
</script>
複製程式碼
頁面展示效果如下:
那麼我們看看在不寫在js
中的圖片引入是否也會出現問題呢?
<template>
<div class="hello">
<img src="../assets/logo.png" alt="logo">
<img src="static/logo.png" alt="logo">
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data() {
return {
}
}
}
</script>
複製程式碼
來看一下頁面的反應:
效果證實,我們在html中的引入方式是不會受到影響的。
那如果我們必須要在js
中使用assets
中的圖片,該怎麼寫呢?
<template>
<div class="hello">
<div v-for="item in cityList" :key="item.id">
<div >{{item.title}}</div>
<div>城市圖片:<img :src="item.img"></div>
</div>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data() {
return {
cityList: [{
title: '北京',
id: "001",
img:require("../assets/logo.png") //使用require()的方式引入即可
},
{
title: '上海',
id: "002",
img: "static/logo.png"
}
]
}
}
}
</script>
複製程式碼
好啦,接下來就是見證奇蹟的時刻了!!
綜上所述,總結為以下兩點:
1.任何放在 static
中檔案需要以絕對路徑的形式引用:/static/imgurl
。
2.static
放不會變動的檔案,assets
放可能會變動的檔案。
參考:https://juejin.im/post/59be4d325188257e764c8485 OBKoro1
十一、關於打包後空白頁面的問題
會在dist 目錄下生成以下檔案 可是當我們執行命令打包後,開啟index.html的時候,顯示空白頁面,而且報錯,指明檔案找不到,如下:vue-cli在執行 npm run build 打包後,
接下來讓我們開啟cofig
資料夾的index.js
,找到build
這個物件,將
assetsPublicPath: '/'
複製程式碼
這個路徑地址改成
assetsPublicPath: './',
複製程式碼
重新執行命令,重新打包,再開啟index.htnl,頁面即可顯示:
assetsPublicPath屬性作用是指定編譯釋出的根目錄,'/'指的是專案的根目錄 ,'./'指的是當前目錄。當我們打包後,index和static是放在dist目錄下,而static是和index是平級的,所以不應該在根目錄查詢檔案。
參考:https://juejin.im/post/59ca4b96f265da0668760b60 OBKoro1
十二、關於非同步懶載入路由的寫法
在vue-cli自帶的腳手架的路由是如下這樣寫的:
import Vue from 'vue'
import Router from 'vue-router'
import bus from '../bus'
import HelloWorld from '@/components/HelloWorld'
Vue.use(Router)
export default new Route({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
]
});
複製程式碼
使用的是import 的方式引入進來的,那麼我們需要使用非同步的方式,該怎麼寫呢?
import Vue from 'vue'
import Router from 'vue-router'
import bus from '../bus'
Vue.use(Router)
var router = new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: (resolve) => require(['@/components/HelloWorld'], resolve),
},
{
path: '/login',
name: 'login',
component: (resolve) => require(['@/login'], resolve),
}
]
});
bus.router = router
export default router
複製程式碼
第二種方式:
const Index = () => import( '@/views/index')
const routers = [
{
path: '/',
name: 'index',
component: Index
}
]
複製程式碼
十三、寫一個自定義指令
在vue中除了可以寫元件,還可以使用自定義指令來實現某些特殊的操作,下面就拿一個類似官方的獲取input焦點的“基本款”的栗子?來演示。 我有個習慣,就是把相同的東西歸類,所以,我先去建了一個資料夾來存放我的指令,如下圖:
詳細程式碼如下: 在這裡定義並匯出我的自定義指令,指令裡包含我想實現的操作。(當前是一個獲取焦點的示例)
export const focus = (el) => {
el.focus()
}
複製程式碼
在使用的頁面,首先將指令檔案引入,然後配置到directive中,在需要使用到標籤內新增,注意指令前需新增:”v-“,如下所示: 我的指令name為focus,在標籤內寫成 “v-focuss”:
<template>
<div>
<input type="text" v-focus>
</div>
</template>
<script>
import { focus } from "../../directives/index"
export default {
name: "",
data() {
return {}
},
directives: {focus}, //自定義指令
components: {},
mounted() {},
methods: {}
}
</script>
<style scoped>
</style>
複製程式碼
vue的自定義指令直接操作dom較方便:
先看
directives/index
頁面 :
接下來看一下呼叫頁面:
最後我們來看一下頁面:
再升級!新增引數的自定義指令
頁面的資料也可以寫成一個變數,使用變數來控制樣式:
下面是自定義指令的生命週期(我們可以在指令的生命週期中做我們想處理的事件):
1.bind
:只呼叫一次,指令第一次繫結到元素時呼叫,用這個鉤子函式可以定義一個繫結時執行一次的初始化動作。
2.inserted
:被繫結元素插入父節點時呼叫(父節點存在即可呼叫,不必存在於document
中)。
3.update
:被繫結於元素所在的模板更新時呼叫,而無論繫結值是否變化。通過比較更新前後的繫結值,可以忽略不必要的模板更新。
4.componentUpdated
:被繫結元素所在模板完成一次更新週期時呼叫。
5.unbind
:只呼叫一次,指令與元素解綁時呼叫
好啦!大功告成,小夥伴們,動手試試吧!
十四、關於打包後大圖片請求不到到問題
今日在專案完成後,進行打包測試,本地開發好好的,但打包後發現登入頁面到背景圖片拿不到,但是其他logo小圖片是可以正常顯示,於是就很鬱悶,第一反應,想著應該是圖片太大了,未被壓縮,然後,就找到了如下位置:
想著把limit的範圍放大,可是那如果還有更大的圖片呢?這並不是個優雅的辦法。於是想到了萬能到度娘,就有了如下解決方法: my.oschina.net/u/1778998/b… css引入圖片再打包後,style-loader無法設定自己的publicPath,所以只要改變style-loader中的publicPath即可,在build/util.js檔案中ExtractTextPlugin的css路徑,手動新增publicPath引數。
新增後,再執行一次build,圖片就可以正常顯示。
十五、跳過無需編譯及避免出現{{}}
在我們的專案中應該會有很多情景,標籤內的內容是不需要編譯的,可是我們的程式碼並不知道,vue提供了一個可以直接跳過編譯的指令,供我們新增在純靜態標籤上。
<div v-pre> 直接跳過不需要編譯的標籤,加快編譯效率</div>
複製程式碼
還有一種情形,在頁面有用到{{}}賦值時,有時我們頁面阻塞或載入跟不上、頻繁重新整理時,可能會顯示未賦值的{{}},等拿到值後才能更新出來,這樣給使用者一種很不友好的體驗,同樣vue也幫我們想到了,vue提供了一個可以等待編譯結束,才會顯示標籤內容到指令.
<div v-cloak> {{message}}直接結束編譯,避免出現閃爍花括號,配合css樣式書寫</div>
//配合css 樣式完成
<style scoped>
[v-cloak]{display: none;}
</style>
複製程式碼
十六、寫一個自定義過濾器
vue有自己自帶的過濾器供我們使用,那我們如何來寫一個自定義過濾器呢?下面跟我一起操作吧!
先去建立一個filter資料夾,來存放你的過濾器,並在檔案中寫出你想執行的過濾器的方法
在頁面的呼叫(類似自定義指令)OBKoro1 的《你或許不知道的Vue的這些小技巧》很實用,推薦給大家!
十七、vuex的簡單實現
程式碼如下:我們都知道vuex是用來實現vue各個元件資料傳輸功能的,不區分父子元件,全域性即可呼叫,讓我們的工程有了一個總的title,下來就讓試試: 先來建一個store,用來存放我們的初始化狀態,以及更改的方法:
接下來讓我們引入必備的依賴,以及相應的預設匯出:
import Vue from 'vue';
import Vuex from 'vuex';
import { state as userState, actions as userActions, mutations as userMutations } from './stores.js';
Vue.use(Vuex);
const state = Object.assign({}, userState);
const mutations = Object.assign({}, userMutations);
const actions = Object.assign({}, userActions);
export default new Vuex.Store({
state,
mutations,
actions
});
複製程式碼
最後讓我們來寫一下定義的初始值以及需要改變的方法:
程式碼如下:import {appRouter} from '../assets/data/menu';
// 初始值
export const state = {
data: "0",
menuList: appRouter,
pageTitle:'初始值'
}
//如何改變 setData方法名
export const mutations = {
setData(state, val) {
state.data = val
},
changePage(state,val){
state.pageTitle = val
}
}
//實現改變
export const actions = {
setData(contex, val) {
contex.commit("setData", val)
},
changePage(contex,val){
contex.commit("changePage", val)
}
}
複製程式碼
使用頁面,直接呼叫即可,不用其他依賴:
// 獲取全域性變數
console.log( this.$store.state.pageTitle) // 初始值
// 更改全域性變數
this.$store.commit('changePage', '門店管理')
複製程式碼
十八、通過路由傳參,獲取引數,用於記錄狀態等
如下圖情況:
我們需要在點選操作列的詳情進入下一個頁面,那麼我們是需要拿到此行的id 值,並且請求資料,然後再去渲染頁面,那麼我們如何通過路由來實現引數的傳遞呢? 借鑑
第一種:通過path,query 來傳參
// 傳參
<div>
<router-link tag="a" :to="{path:'detail',query:{id:1}}" >詳情</router-link>
</div>
複製程式碼
// 接收引數
<script>
export default{
mounted (){
const id = this.$route.query.id; //可以拿到從列表頁傳過來的id
}
}
</script>
複製程式碼
第二種:通過name,param 來傳參
// 傳參
<div>
<router-link tag="a" :to="{name:'detail',params:{id:1}}" >詳情</router-link>
</div>
複製程式碼
// 接收引數
<script>
export default{
mounted (){
const id = this.$route.params.id; //可以拿到從列表頁傳過來的id
}
}
</script>
複製程式碼
上面兩個大同小異,接下來我們試試傳動態的引數:
// 傳參
<div>
<router-link tag="a" :to="{name:'detail',params:{id:val}}" >詳情</router-link>
</div>
複製程式碼
// 接收引數
<script>
export default{
data () {
val:1212
},
mounted () {
const val = this.$route.params.val; //可以拿到從列表頁傳過來的val值
}
}
</script>
複製程式碼
繼續升級,接下來我們試試,傳多個動態引數,每個key用逗號分割即可:
// 傳參
<div>
<router-link tag="a" :to="{name:'detail',params:{id:id,name:name,age:age}}" >詳情</router-link>
</div>
複製程式碼
// 接收引數
<script>
export default{
data () {
id:1212,
name:"張小一",
age:10
},
mounted () {
const id = this.$route.params.id; //可以拿到從列表頁傳過來的id值
const name = this.$route.params.name; //可以拿到從列表頁傳過來的name值
const age = this.$route.params.age; //可以拿到從列表頁傳過來的age值
}
}
</script>
複製程式碼
再升級,我們接下來傳一個陣列改如何操作
// 傳參
<div>
<router-link tag="a" :to="{name:'detail',params:{list:[1,2,3,4]}}">詳情</router-link>
</div>
複製程式碼
// 接收引數
<script>
export default{
data () {
arr:
},
mounted () {
const list = this.$route.params.list; //可以拿到從列表頁傳過來的list陣列
}
}
</script>
複製程式碼
!!!⚠️注意:一般情況下不建議使用路由傳過多的引數
十九、關於跳轉路由後,清楚計時器的解決方法
某天有看到一篇大佬的文章,講述的是跳轉頁面後,原頁面計時器仍然在執行的問題,正好自己也有寫國一個實時的鐘表的demo,於是就實驗了一番:
頁面如下:
在每次進入頁面後呼叫了setTimeout,每秒去更新時間,為了驗證切換路由後,是否還會呼叫計時器,我在計時器後面加了一個列印數值來觀察,如下:
...
...
...
this.inif.oSecond = seconds;
this.inif.seconds = seconds * 6;
this.inif.minute = minutes * 6 + seconds * (6 / 60);
this.inif.hour = (hours - 12) * 30 + minutes * (360 / 12 / 60);
//呼叫計時器
this.timer = setTimeout(this.time, 1000)
//列印參考值
console.log(this.inif.seconds)
複製程式碼
可以看到後臺的列印情況:
現在我們切換路由去往其他的頁面,看看計時器是否停止:
實際證明,它並沒有停止,計時器依然在執行。這樣是非常消耗效能的。接下來我們來看看,大神是怎麼解決的:
第一種解決方案:
在beforeDestroy
生命週期內進行清除:
beforeDestroy() {
clearInterval(this.timer);
this.timer = null;
}
複製程式碼
鑑於上面的方法,大神給出解釋:我們的程式碼獨立於清理程式碼,此種操作使得我們比較難於程式化的清理我們建立的所有東西。
第二種解決方案:
通過$once
來監聽定時器,在beforeDestroy
鉤子可以被清除
...
...
...
this.timer = setTimeout(this.time, 1000)
this.$once('hook:beforeDestroy', () => {
clearInterval(this.timer);
})
複製程式碼
兩種解決方案都可以將我們的問題解決,相對來說第二種較優雅!!! 借鑑於 chinaBerg 大神
二十、關於打包後在dist
資料夾的js
裡面會有很多.map
檔案
專案打包後,程式碼都是經過壓縮加密的,如果執行時報錯,輸出的錯誤資訊無法準確得知是哪裡的程式碼報錯。而生成的
.map
字尾的檔案,就可以像沒有加密的程式碼一樣,可以準確定位到錯誤的位置,可以通過設定來不生成該類檔案,因為我們在生成環境是不需要.map
檔案的,所以可以在打包時不用生成這些檔案。
解決方案:
在config/index.js檔案中,設定productionSourceMap: false,就可以不生成.map檔案
二十一、監聽當前vue
的url
路徑,發生變化時重新整理頁面
首先我將我需要跳轉的資訊使用組合完整,如下:此需求是由於專案中一個列表中詳情點選後需要重新請求當前列的
id
,重新繪製當前頁面,如下:
this.$router.push({
path: '/crowdmanage/crowddetails',
query: {
name: 'detail',
id: 17
}
});
複製程式碼
點選後url
確實發生了變化,但vue並沒有檢測到,也就是url
變化了,頁面並沒有重新去請求??????到底是什麼情況????---(此時第一感覺是:我的跳轉方式哪裡出現了問題嗎?為什麼vue 檢測不到呢?或者我要換成原生的跳轉??.....)
去諮詢了團隊的前端小哥哥,小哥哥給出了以下方式解決:---》》》》
由於我的頁面元件裡面巢狀了小的元件,所以我需要在跳轉到的.vue
的頁面新增:
watch: {
$route(to, from) {
this.initData();
}
}
複製程式碼
this.initData()
是所有的請求資訊,當url發生變化後,watch
就可以監聽到,然後重新去請求資料。啦啦啦啦啦 解決了。。。。。感謝小哥哥!!!
二十二、編寫動態元件
此時,我們可以把這三個寫成動態元件,將其包裹在一個此時場景為:當一個元件裡面有3塊內容,而且這三塊內容每次展示都只展示一個
tab
,不會同時展現,如下圖:
index
檔案裡。
首先,我們先建一個主
index
檔案,用於包裹三個子檔案,再建三個子的.vue
檔案,這四個檔案並列即可。
index.vue
主檔案內容如下(以下tabs
來自UI
元件iview
):
<template>
<div>
<Tabs size="small" @on-click="tabChange" v-model="tabContent">
<TabPane v-for="(item,index) in tabList" :key="index" :label="item.label" :name="item.name"></TabPane>
</Tabs>
<--用:is的方式繫結動態變數,變數改變,隨之顯示的元件切換-->
<component :is="tabView"></component>
</div>
</template>
<script>
//引入三個子元件
import A from "./A"
import B from "./B"
import C from "./C"
export default {
data() {
return {
tabContent:"",
tabView: "",
tabList: [{
name: "a",
label: "標籤a"
},
{
name: "b",
label: "標籤b"
},
{
name: "c",
label: "標籤c"
}
],
}
},
// 註冊元件
components: {
A, // 標籤a
B, // 標籤b
C, // 標籤c
},
mounted() {
this.tabChange(name)
},
methods: {
//切換tab事件
tabChange(name) {
this.tabView="A";
this.tabContent = name || "a";
if (name === "a") {
this.tabView = A;
} else if (name === "b") {
this.tabView = B
}else if (name === "c") {
this.tabView = C
}
},
},
watch: {}
}
</script>
<style scoped lang="less">
</style>
複製程式碼
子元件的A.vue
的檔案內容如下:
<template>
<!-- 第一個tab頁的內容 -->
<div>
我是標籤a的內容
</div>
</template>
<script>
export default {
data() {
return {
}
},
props: {},
components: {},
mounted() {},
methods: {},
watch: {}
}
</script>
<style scoped lang="less">
</style>
複製程式碼
其他幾個子檔案也如同A檔案一樣,這樣點選不同的tab
就會請求不同的.vue
檔案。
二十三、keep-alive
快取動態元件,以及它的引數,主要用於保留元件狀態或避免重新渲染。
<keep-alive>
包裹動態元件時,會快取不活動的元件例項,而不是銷燬它們。
Props
:
include
- 字串或正規表示式。只有名稱匹配的元件會被快取。exclude
- 字串或正規表示式。任何名稱匹配的元件都不會被快取。max
- 數字。最多可以快取多少元件例項。
<!-- 基本 -->
<keep-alive>
<component :is="view"></component>
</keep-alive>
<!-- 多個條件判斷的子元件 -->
<keep-alive>
<comp-a v-if="a > 1"></comp-a>
<comp-b v-else></comp-b>
</keep-alive>
<!-- 和 `<transition>` 一起使用 -->
<transition>
<keep-alive>
<component :is="view"></component>
</keep-alive>
</transition>
複製程式碼
注意,``是用在其一個直屬的子元件被開關的情形。如果你在其中有 `v-for` 則不會工作。如果有上述的多個條件性的子元素,`` 要求同時只有一個子元素被渲染。
include
和exclude
屬性允許元件有條件地快取。二者都可以用逗號分隔字串、正規表示式或一個陣列來表示:
<!-- 逗號分隔字串 -->
<keep-alive include="a,b">
<component :is="view"></component>
</keep-alive>
<!-- 正規表示式 (使用 `v-bind`) -->
<keep-alive :include="/a|b/">
<component :is="view"></component>
</keep-alive>
<!-- 陣列 (使用 `v-bind`) -->
<keep-alive :include="['a', 'b']">
<component :is="view"></component>
</keep-alive>
複製程式碼
max
最多可以快取多少元件例項。一旦這個數字達到了,在新例項被建立之前,已快取元件中最久沒有被訪問的例項會被銷燬掉。
<keep-alive :max="10">
<component :is="view"></component>
</keep-alive>
複製程式碼
二十四、父子元件傳遞引數 props
首先來寫一個父子元件傳參的例子?: 父元件內容:
<template>
<div>
下面是引入的元件:
<template-a :isItem="item"><template-a/>
</div>
</template>
<script>
import templateA from "./templateA"
export default {
data () {
return {
item:"000"
}
},
components: {
templateA
},
methods: {
},
mounted () {
}
}
</script>
<style>
</style>
複製程式碼
子元件內容:
<template>
<div>
我是templateA 元件,這是從父元件傳過來的引數: {{isItem}}
</div>
</template>
<script>
export default {
data () {
return {
}
},
props:{
isItem:{
type:String,
default:""
}
},
components: {
},
methods: {
},
mounted () {
}
}
</script>
<style>
</style>
複製程式碼
給props
配置多個型別
例如有時我們在傳遞引數的時候,不確定拿到是什麼型別,有可能是
Number
有可能是String
,此時我們就可給props
的預設型別時新增一個陣列,如下:
props:{
data: {
type: [String, Number],
default: ''
},
}
複製程式碼
這樣在拿到引數的時候,無論是string
還是number
都不會因為型別錯誤而報錯,加大了傳參的容錯率。
詳細參考
- 補充:
props
執行的比data
早,所以在data中可以拿到props
中的傳值。
二十五、 非常好用的計算屬性 computed
在我們的日常編碼中,往往會遇到很多需要判斷的條件、計算資料或者控制許可權等,如下:
條件判斷: AA&&BB&&cc ;
計算資料: A+B-C-D 、 message.split('').reverse().join('');
控制許可權: A === B || B===C ;
複製程式碼
以上的內容我們可以在標籤或者模版
{{}}
中進行判斷,計算,但如果邏輯較多,或者條件較複雜,這樣還在標籤或者模版上進行操作的話,我們的程式碼就看起來會很難理解,而且很冗餘,這時,我們可以把這些複雜的邏輯判斷放到computed
中進行計算,返給模版一個變數即可:
<template>
<div id="example">
<p>未計算前的值: "{{ message }}"</p>
<p>計算完畢返回的值: "{{ reversedMessage }}"</p>
</div>
</template>
<script>
export default {
data () {
return {
message: 'Hello',
}
},
computed: {
// 計算屬性的 getter 在這裡面進行一系列的計算,最後return出一個結果給模版
reversedMessage: function () {
// `this` 指向 vm 例項
return this.message.split('').reverse().join('*')
}
},
components: {
},
methods: {
},
mounted () {
}
}
</script>
<style>
</style>
複製程式碼
頁面展示效果如下:
計算屬性是基於它們的依賴進行快取的。只在相關依賴發生改變時它們才會重新求值。這就意味著只要
message
還沒有發生改變,多次訪問reversedMessage
計算屬性會立即返回之前的計算結果,而不必再次執行函式。
參考:vue-computed
二十六、元件之間的傳參 bus
關於元件和元件之間的引數傳遞(非父子),
vue
推薦使用bus
來進行傳遞,可進行上行、下行、平行、斜行各種傳遞,下面我們就來用bus來驗證。 首先需要先將它建立出來,可以放在公用的工具js
中,最後統一引入到全域性mian.js
中或者直接在mian
中都可以,根據你情況建立並引入就行:
import Vue from "vue";
export default new Vue()
複製程式碼
此時就可以直接用了,下面讓我們來傳個引數試試:
A頁面:
<template>
<div id="example">
<Button @click="searIconClick" slot="append" icon="ios-search"></Button>
</div>
</template>
<script>
export default {
data () {
return {
message: 'Hello',
}
},
methods: {
// 當點選按鈕後,將message使用$emit傳給B頁面
searIconClick(){
this.bus.$emit("searInfo", this.message);
}
},
}
</script>
複製程式碼
B頁面:
<template>
<div id="example">
{{value}}
</div>
</template>
<script>
export default {
data () {
return {
value: '',
}
},
components: {
},
methods: {
},
mounted () {
this.bus.$on('searInfo', (message) => {
this.value = message;
});
}
}
</script>
<style>
</style>
複製程式碼
A
頁面傳送的事件名和B
頁面接受的事件名必須一致,而且需是全專案唯一的,不然會被其他傳參影響,或者影響其他傳參,我之前就出過這樣的錯,讓小姐姐找問題找來很久? !
二十七、 計算屬性conputed,用來處理資料計算
在我們專案中,有時需要進行一些計算,只要資料改變,計算實時更新,如資料不發生變化,快取計算結果。 效果展示地址:
二十八、 vue中的錨連結跳轉
在
vue
中的錨連結和普通的html
不同,關於vue
中的錨連結可以參考vue
中的scrollBehavior
滾動行為
----------------廢話不多說,直接上程式碼-----------
在router.js
中的router
例項中
const router = new VueRouter({
routes,
mode: 'history',
scrollBehavior(to, from, savedPosition) {
if (to.hash) {
return {
selector: to.hash
}
}
}
})
export default router;
複製程式碼
在vue
中點選跳轉的位置 使用<a>
連結包起來
<div>
<a href="#populationInformation">A</a>
</div>
<div>
<a href="#peopleCounting">B</a>
</div>
<div>
<a href="#trafficAnalysis">C</a>
</div>
複製程式碼
在需要跳轉到的位置
<div id='populationInformation '> A跳轉到此</div>
<div id='peopleCounting'> B跳轉到此</div>
<div id='trafficAnalysis '>C跳轉到此</div>
複製程式碼
要保證<a>
標籤的 href 的地址要和下面id
的值是相同的才可以完成相應的跳轉,
至於在router
中的配置也是必須的。
二十九、 vue如何獲取當前頁面的url地址
當場景需要我們獲取url地址,以做某些判斷操作時,我們可以使用下面的方法來獲取。
1.獲取全部url
console.log("完整的url地址:",window.location.href)
// 完整的url地址: https://juejin.im/editor/posts/5a1a6a6551882534af25a86b
複製程式碼
2.獲取路由路徑
console.log("路由路徑:",this.$route.path)
// 路由路徑:/activity/list
複製程式碼
3.獲取路徑引數
console.log("路徑引數:",this.$route.query)
// 路徑引數: {name: "detail", id: "109", tabView: "self", groupID: ""}
複製程式碼
(參考:十八、通過路由傳參,獲取引數,用於記錄狀態等)
三十、兩種前端下載方式
1.通過後端介面直接通過url跳轉到下載地址即可
window.location.replace(http://172.******/exports/${id}/download`)
複製程式碼
2.通過後端介面前端實現下載請求
this.$axios.get(`${this.$config.apiDomain}/crowds/exports/${row.id}/download-crowd`)
.then(({data})=>{
// data 直接傳入now Blob中
const blob = new Blob([data], { type: 'cache-control,expires,pragma,content-type' })
const downloadElement = document.createElement('a')
const href = window.URL.createObjectURL(blob)
downloadElement.href = href
downloadElement.download = row.id+'.csv'
document.body.appendChild(downloadElement)
downloadElement.click()
document.body.removeChild(downloadElement) // 下載完成移除元素
window.URL.revokeObjectURL(href) // 釋放掉blob對
})
複製程式碼
借鑑地址
值得推薦:
- vue的程式碼風格指南 裡面有vue 推薦的程式碼編寫風格,強烈推薦的,推薦及謹慎使用的各種風格示例,推薦大家看看,有助於開發效率提升。
- vue的網頁執行工具 iVuewRun網頁版的vue,可直接執行使用,還可以分享給小夥伴!
接下來我還會持續追加,看文章的小夥伴們可以新增一下關注哦!
作者:Christine
出處:https://juejin.im/post/5a125827518825293b4fea8a
版權所有,歡迎保留原文連結進行轉載:)
複製程式碼
如果你對我對文章感興趣或者有些建議想說給我聽?,也可以新增一下微信哦!
如果親感覺我的文章還不錯的話,可以一下新增關注哦!最後:
祝各位工作順利!
-小菜鳥Christine
複製程式碼