web前端---作為一位Vue工程師,這些開發技巧你都會嗎?
路由引數解耦
一般在元件內使用路由引數,大多數人會這樣做:
export
default
{
methods
:
{
getParamsId
()
{
return
this
。
$route
。
params
。
id
}
}
}
在元件中使用 $route 會使之與其對應路由形成高度耦合,從而使元件只能在某些特定的 URL 上使用,限制了其靈活性。
正確的做法是透過 props 解耦
const
router
=
new
vueRouter
({
routes
:
[{
path
:
‘/user/:id’
,
component
:
User
,
props
:
true
}]
})
將路由的 props 屬性設定為 true 後,元件內可透過 props 接收到 params 引數
export
default
{
props
:
[
‘id’
],
methods
:
{
getParamsId
()
{
return
this
。
id
}
}
}
另外你還可以透過函式模式來返回 props
const
router
=
new
vueRouter
({
routes
:
[{
path
:
‘/user/:id’
,
component
:
User
,
props
:
(
route
)
=>
({
id
:
route
。
query
。
id
})
}]
})
文件:
https://
router。vuejs。org/zh/gui
de/essentials/passing-props。html
函式式元件
函式式元件是無狀態,它無法例項化,沒有任何的生命週期和方法。建立函式式元件也很簡單,只需要在模板新增 functional 宣告即可。一般適合只依賴於外部資料的變化而變化的元件,因其輕量,渲染效能也會有所提高。
元件需要的一切都是透過 context 引數傳遞。它是一個上下文物件,具體屬性檢視 文件 。這裡 props 是一個包含所有繫結屬性的物件。
函式式元件
<
template
functional
>
<
div
class
=
“list”
>
<
div
class
=
“item”
v-for
=
“item in props。list”
:key
=
“item。id”
@
click
=
“props。itemClick(item)”
>
<
p
>
{{item。title}}
p
>
<
p
>
{{item。content}}
p
>
div
>
div
>
template
>
父元件使用
<
template
>
<
div
>
<
List
:list
=
“list”
:itemClick
=
“item => (currentItem = item)”
/>
div
>
template
>
import
List
from
‘@/components/List。vue’
export
default
{
components
:
{
List
},
data
()
{
return
{
list
:
[{
title
:
‘title’
,
content
:
‘content’
}],
currentItem
:
‘’
}
}
}
文件:
https://
cn。vuejs。org/v2/guide/r
ender-function。html
樣式穿透
在開發中修改第三方元件樣式是很常見,但由於 scoped 屬性的樣式隔離,可能需要去除 scoped 或是另起一個 style 。
這些做法都會帶來副作用(元件樣式汙染、不夠優雅),樣式穿透在css預處理器中使用才生效。
我們可以使用 >>> 或 /deep/ 解決這一問題:
<
style
scoped
>
外層
>>>
。
el-checkbox
{
display
:
block
;
font-size
:
26
px
;
。el-checkbox__label
{
font-size
:
16
px
;
}
}
style
>
<
style
scoped
>
/
deep
/
。
el-checkbox
{
display
:
block
;
font-size
:
26
px
;
。el-checkbox__label
{
font-size
:
16
px
;
}
}
style
>
watch高階使用
立即執行
watch 是在監聽屬性改變時才會觸發,有些時候,我們希望在元件建立後 watch 能夠立即執行
可能想到的的方法就是在 create 生命週期中呼叫一次,但這樣的寫法不優雅,或許我們可以使用這樣的方法
export
default
{
data
()
{
return
{
name
:
‘Joe’
}
},
watch
:
{
name
:
{
handler
:
‘sayName’
,
immediate
:
true
}
},
methods
:
{
sayName
()
{
console
。
log
(
this
。
name
)
}
}
}
深度監聽
在監聽物件時,物件內部的屬性被改變時無法觸發 watch ,我們可以為其設定深度監聽
export
default
{
data
:
{
studen
:
{
name
:
‘Joe’
,
skill
:
{
run
:
{
speed
:
‘fast’
}
}
}
},
watch
:
{
studen
:
{
handler
:
‘sayName’
,
deep
:
true
}
},
methods
:
{
sayName
()
{
console
。
log
(
this
。
studen
)
}
}
}
觸發監聽執行多個方法
使用陣列可以設定多項,形式包括字串、函式、物件
export
default
{
data
:
{
name
:
‘Joe’
},
watch
:
{
name
:
[
‘sayName1’
,
function
(
newVal
,
oldVal
)
{
this
。
sayName2
()
},
{
handler
:
‘sayName3’
,
immaediate
:
true
}
]
},
methods
:
{
sayName1
()
{
console
。
log
(
‘sayName1==>’
,
this
。
name
)
},
sayName2
()
{
console
。
log
(
‘sayName2==>’
,
this
。
name
)
},
sayName3
()
{
console
。
log
(
‘sayName3==>’
,
this
。
name
)
}
}
}
文件:
https://
cn。vuejs。org/v2/api/#
watch
watch監聽多個變數
watch本身無法監聽多個變數。但我們可以將需要監聽的多個變數透過計算屬性返回物件,再監聽這個物件來實現“監聽多個變數”
export
default
{
data
()
{
return
{
msg1
:
‘apple’
,
msg2
:
‘banana’
}
},
compouted
:
{
msgObj
()
{
const
{
msg1
,
msg2
}
=
this
return
{
msg1
,
msg2
}
}
},
watch
:
{
msgObj
:
{
handler
(
newVal
,
oldVal
)
{
if
(
newVal
。
msg1
!=
oldVal
。
msg1
)
{
console
。
log
(
‘msg1 is change’
)
}
if
(
newVal
。
msg2
!=
oldVal
。
msg2
)
{
console
。
log
(
‘msg2 is change’
)
}
},
deep
:
true
}
}
}
事件引數$event
$event 是事件物件的特殊變數,在一些場景能給我們實現複雜功能提供更多可用的引數
原生事件
在原生事件中表現和預設的事件物件相同
<
template
>
<
div
>
<
input
type
=
“text”
@
input
=
“inputHandler(‘hello’, $event)”
/>
div
>
template
>
export
default
{
methods
:
{
inputHandler
(
msg
,
e
)
{
console
。
log
(
e
。
target
。
value
)
}
}
}
自定義事件
在自定義事件中表現為捕獲從子元件丟擲的值
my-item。vue :
export
default
{
methods
:
{
customEvent
()
{
this
。
$emit
(
‘custom-event’
,
‘some value’
)
}
}
}
App。vue
<
template
>
<
div
>
<
my-item
v-for
=
“(item, index) in list”
@
custom-event
=
“customEvent(index, $event)”
>
my-list
>
div
>
template
>
export
default
{
methods
:
{
customEvent
(
index
,
e
)
{
console
。
log
(
e
)
// ‘some value’
}
}
}
文件:
https://
cn。vuejs。org/v2/guide/e
vents。html
自定義元件雙向繫結
元件 model 選項:
允許一個自定義元件在使用 v-model 時定製 prop 和 event。預設情況下,一個元件上的 v-model 會把 value 用作 prop 且把 input 用作 event,但是一些輸入型別比如單選框和複選框按鈕可能想使用 value prop 來達到不同的目的。使用 model 選項可以迴避這些情況產生的衝突。
input 預設作為雙向繫結的更新事件,透過 $emit 可以更新繫結的值
<
my-switch
v-model
=
“val”
>
my-switch
>
export
default
{
props
:
{
value
:
{
type
:
Boolean
,
default
:
false
}
},
methods
:
{
switchChange
(
val
)
{
this
。
$emit
(
‘input’
,
val
)
}
}
}
修改元件的 model 選項,自定義繫結的變數和事件
<
my-switch
v-model
=
“num”
value
=
“some value”
>
my-switch
>
export
default
{
model
:
{
prop
:
‘num’
,
event
:
‘update’
},
props
:
{
value
:
{
type
:
String
,
default
:
‘’
},
num
:
{
type
:
Number
,
default
:
0
}
},
methods
:
{
numChange
()
{
this
。
$emit
(
‘update’
,
num
++
)
}
}
}
文件:
https://
cn。vuejs。org/v2/api/#
model
監聽元件生命週期
通常我們監聽元件生命週期會使用 $emit ,父元件接收事件來進行通知
子元件
export
default
{
mounted
()
{
this
。
$emit
(
‘listenMounted’
)
}
}
父元件
<
template
>
<
div
>
<
List
@
listenMounted
=
“listenMounted”
/>
div
>
template
>
其實還有一種簡潔的方法,使用 @hook 即可監聽元件生命週期,元件內無需做任何改變。同樣的, created 、 updated 等也可以使用此方法。
<
template
>
<
List
@
hook
:
mounted
=
“listenMounted”
/>
<
/template>
程式化的事件偵聽器
比如,在頁面掛載時定義計時器,需要在頁面銷燬時清除定時器。這看起來沒什麼問題。但仔細一看 this。timer 唯一的作用只是為了能夠在 beforeDestroy 內取到計時器序號,除此之外沒有任何用處。
export
default
{
mounted
()
{
this
。
timer
=
setInterval
(()
=>
{
console
。
log
(
Date
。
now
())
},
1000
)
},
beforeDestroy
()
{
clearInterval
(
this
。
timer
)
}
}
如果可以的話最好只有生命週期鉤子可以訪問到它。這並不算嚴重的問題,但是它可以被視為雜物。
我們可以透過 $on 或 $once 監聽頁面生命週期銷燬來解決這個問題:
export
default
{
mounted
()
{
this
。
creatInterval
(
‘hello’
)
this
。
creatInterval
(
‘world’
)
},
creatInterval
(
msg
)
{
let
timer
=
setInterval
(()
=>
{
console
。
log
(
msg
)
},
1000
)
this
。
$once
(
‘hook:beforeDestroy’
,
function
()
{
clearInterval
(
timer
)
})
}
}
使用這個方法後,即使我們同時建立多個計時器,也不影響效果。因為它們會在頁面銷燬後程序化的自主清除。
手動掛載元件
在一些需求中,手動掛載元件能夠讓我們實現起來更加優雅。比如一個彈窗元件,最理想的用法是透過命令式呼叫,就像 elementUI 的 this。$message 。而不是在模板中透過狀態切換,這種實現真的很糟糕。
先來個最簡單的例子:
import
vue
from
‘vue’
import
Message
from
‘。/Message。vue’
// 構造子類
let
Messageconstructor
=
vue
。
extend
(
Message
)
// 例項化元件
let
messageInstance
=
new
Messageconstructor
()
// $mount可以傳入選擇器字串,表示掛載到該選擇器
// 如果不傳入選擇器,將渲染為文件之外的的元素,你可以想象成 document。createElement()在記憶體中生成dom
messageInstance
。
$mount
()
// messageInstance。$el獲取的是dom元素
document
。
body
。
appendChild
(
messageInstance
。
$el
)
下面實現一個簡易的 message 彈窗元件
Message/index。vue
<
template
>
<
div
class
=
“wrap”
>
<
div
class
=
“message”
:class
=
“item。type”
v-for
=
“item in notices”
:key
=
“item。_name”
>
<
div
class
=
“content”
>
{{item。content}}
div
>
div
>
div
>
template
>
// 預設選項
const
DefaultOptions
=
{
duration
:
1500
,
type
:
‘info’
,
content
:
‘這是一條提示資訊!’
,
}
let
mid
=
0
export
default
{
data
()
{
return
{
notices
:
[]
}
},
methods
:
{
add
(
notice
=
{})
{
// name標識 用於移除彈窗
let
_name
=
this
。
getName
()
// 合併選項
notice
=
Object
。
assign
({
_name
},
DefaultOptions
,
notice
)
this
。
notices
。
push
(
notice
)
setTimeout
(()
=>
{
this
。
removeNotice
(
_name
)
},
notice
。
duration
)
},
getName
()
{
return
‘msg_’
+
(
mid
++
)
},
removeNotice
(
_name
)
{
let
index
=
this
。
notices
。
findIndex
(
item
=>
item
。
_name
===
_name
)
this
。
notices
。
splice
(
index
,
1
)
}
}
}
。
wrap
{
position
:
fixed
;
top
:
50
px
;
left
:
50
%
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
transform
:
translateX
(
-50
%
);
}
。
message
{
——borderWidth
:
3
px
;
min-width
:
240
px
;
max-width
:
500
px
;
margin-bottom
:
10
px
;
border-radius
:
3
px
;
box-shadow
:
0
0
8
px
#ddd
;
overflow
:
hidden
;
}
。
content
{
padding
:
8
px
;
line-height
:
1。3
;
}
。
message
。
info
{
border-left
:
var
(
——
borderWidth
)
solid
#909399
;
background
:
#F4F4F5
;
}
。
message
。
success
{
border-left
:
var
(
——
borderWidth
)
solid
#67C23A
;
background
:
#F0F9EB
;
}
。
message
。
error
{
border-left
:
var
(
——
borderWidth
)
solid
#F56C6C
;
background
:
#FEF0F0
;
}
。
message
。
warning
{
border-left
:
var
(
——
borderWidth
)
solid
#E6A23C
;
background
:
#FDF6EC
;
}
Message/index。js
import
Vue
from
‘vue’
import
Index
from
‘。/index。vue’
let
messageInstance
=
null
let
Messageconstructor
=
Vue
。
extend
(
Index
)
let
init
=
()
=>
{
messageInstance
=
new
Messageconstructor
()
messageInstance
。
$mount
()
document
。
body
。
appendChild
(
messageInstance
。
$el
)
}
let
caller
=
(
options
)
=>
{
if
(
!
messageInstance
)
{
init
(
options
)
}
messageInstance
。
add
(
options
)
}
export
default
{
// 返回 install 函式 用於 Vue。use 註冊
install
(
vue
)
{
vue
。
prototype
。
$message
=
caller
}
}
main。js
import
Message
from
‘@/components/Message/index。js’
Vue
。
use
(
Message
)
使用
this
。
$messagae
({
type
:
‘success’
,
content
:
‘成功資訊提示’
,
duration
:
3000
})
文件:
https://
cn。vuejs。org/v2/api/#
vm-mount
作為一名web前端工程師,這些開發技巧你都會麼?
web前端全系列資料已經打包好了,希望能到各位!!!
上一篇:傳統文化怎麼能少得了她?