也多是由於接觸vue時間也不長,常常落入不知名的‘坑’中,對於我這個菜鳥來講,每次‘落坑’無疑是一場不小的災難。前兩天有個朋友在問我,在使用
vue
中有沒有遇到一些很難解決的問題,一下我也只能說出一兩個,正所謂‘光說不練,假把式’,因此索性就抽時間總結一下我在項目中遇到的vue
的問題,也貼出了效果圖片,這樣看起來也比較清晰。有寫的不對的地方,在您時間還容許的狀況下,還勞煩你們告訴我哦,我也好儘早修改,以避免給看文章的其餘同仁帶來沒必要要的麻煩!(當前版本:"vue@2.5.3") -------------------在此謝過!-----------css
說到vue的實戰,不得不說vue
項目建立,那麼關於vue cli
項目搭建,我在以前的文章中有專門寫過,可參考個人第一篇文章: vue cli 框架搭建html
每一個Vue實例在被建立以前都要通過一系列的初始化過程,這個過程就是vue的生命週期前端
方法名 | 狀態 | 含義 |
---|---|---|
beforeCreate | creating | 所有實例建立以前,獲取不到props 和data中的數據 |
created | creating | 實例建立成功,能夠拿到data中的數據 |
beforeMount | mounting | 此時data裏面的數據和模板已生成html |
mounted | mounting | 掛載結束,模版中的 data 數據直接顯示出來了,此時通常能夠作一些ajax操做 |
beforeUpdate | updating | 當 data 數據發生變化調用,發生在虛擬 DOM 從新渲染和打補丁以前 |
updated | updating | 數據更改致使的虛擬 DOM 從新渲染和打補丁 |
beforeDestroy | destroying | 在 vue 實例銷燬以前調用,此時實例任然可用,通常在這一步作一些重置的操做,好比清除掉組件中的定時器 和 監聽的dom事件 |
destroyed | destroying | 在 vue 實例銷燬以後調用,vue 實例指示的全部東西都會解綁定,全部的事件監聽器會被移除,全部的子實例也會被銷燬 |
⚠️注意:vue
若是在created
階段的發送ajax
請求,此時頁面視圖未出現,若是請求信息過多,頁面會長時間處於白屏狀態,請求建議放在mounted
階段,固然mounted
不會承諾全部的子組件也都一塊兒被掛載。若是你但願等到整個視圖都渲染 完畢再發生請求,能夠用 vm.$nextTick
。webpack
子組件完成掛載後,父組件纔會掛載,銷燬父組件時,先將子組件銷燬後纔會銷燬父組件ios
參考地址web
加載渲染過程:ajax
父beforeCreate -》父created -》父beforeMount-》子beforeCreate -》子created-》子beforeMount-》子 mounted-》父mouted
複製代碼
子組件更新過程:正則表達式
父beforeUpdate -》子 beforeUpdate -》子 update -》父update
複製代碼
父組件更新過程:vue-router
父beforeUpdate -》父update
複製代碼
銷燬過程:
父beforeDestroy -》子beforeDestroy -》子 destroy -》父 destroy
複製代碼
分享:自用的vue模版
<template>
<div>
</div>
</template>
<script>
export default {
props:{},
data() {
return {}
},
computed:{},
components: {},
created(){},
mounted() {},
methods: {},
watch: {},
destroyed(){},
}
</script>
<style scoped lang="less">
</style>
複製代碼
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/...
複製代碼
@/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
....均可以哦!快去動手試試吧!!
router
在咱們的實際業務中,有時須要在某一組件內,點擊一個按鈕或者是點擊一個連接切換跳轉到其餘組件,也就是跳轉路由,咱們能夠試試下面的方法:
//直接跳轉
this.$router.push('/map')
//條件容許時跳轉
if(this.data){
this.$router.push('/map')
}
複製代碼
注意:
router
須要掛在到vue
實例上,這樣才能夠獲取到this.$router
,並且push
後面的括號中的路由地址,也須要在vue
的router
中有註冊,最後,在('')中填寫你須要跳轉的路由便可完成跳轉。
上面剛剛有講到路由router
,接下來再講一個和router
相關的方法go
,這個方法是用做前進後退導航來使用的,有時實際業務須要咱們添加一個返回上一頁面的功能,那麼咱們就能夠用go
來實現。當爲‘-1’時就能夠後退到上一個路由頁面。
this.$router.go('-1')
複製代碼
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
放可能會變更的文件。
參考:juejin.im/post/59be4d… OBKoro1
vue-cli在執行 npm run build 打包後,
接下來讓咱們打開cofig
文件夾的index.js
,找到build
這個對象,將
assetsPublicPath: '/'
複製代碼
這個路徑地址改爲
assetsPublicPath: './',
複製代碼
從新執行命令,從新打包,再打開index.htnl,頁面便可顯示:
assetsPublicPath屬性做用是指定編譯發佈的根目錄,'/'指的是項目的根目錄 ,'./'指的是當前目錄。當咱們打包後,index和static是放在dist目錄下,而static是和index是平級的,因此不該該在根目錄查找文件。
參考:juejin.im/post/59ca4b… 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的偏門操做,分享給你們: juejin.im/post/5adc99…
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是用來實現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>
複製代碼
**⚠️注意:取參數時用的是this.$route
,而不是this.$router
。
上面兩個大同小異,接下來咱們試試傳動態的參數:
// 傳參
<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
頁面接受的事件名必須一致,並且需是全項目惟一的,否則會被其餘傳參影響,或者影響其餘傳參,我以前就出過這樣的錯,讓小姐姐找問題找來好久😂 !
在咱們項目中,有時須要進行一些計算,只要數據改變,計算實時更新,如數據不發生變化,緩存計算結果。 效果展現地址:
在
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
中的配置也是必須的。
當場景須要咱們獲取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: ""}
複製代碼
(參考:十8、經過路由傳參,獲取參數,用於記錄狀態等)
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對
})
複製代碼
現階段咱們前端開發者作項目通常手裏都有各類各樣的
UI
庫,例如vue
的UI
庫有iview
,elementUI
等等,UI
庫的組件都會提供一些須要的事件,你可能有不少次想要在一個組件的根元素上直接監聽一個原生事件。這時,你可使用v-on
的.native
修飾符:
<base-input v-on:focus.native="onFocus"></base-input>
複製代碼
值得推薦:
接下來我還會持續追加,看文章的小夥伴們能夠添加一下關注哦!
做者:Christine
出處:https://juejin.im/post/5a125827518825293b4fea8a
版權全部,歡迎保留原文連接進行轉載:)
複製代碼
若是你對我對文章感興趣或者有些建議想說給我聽👂,也能夠添加一下微信哦!
PS:目前找工做中,求大佬們內推,中高級前端,偏JS,Vue,北京。
郵箱:christine_lxq@sina.com
最後:
祝各位工做順利!
-小菜鳥Christine
複製代碼