在上篇中介紹了一個 property 物件能夠設置的 key,與相關綁定的知識。而關於物件和陣列的操作與其他的型別有些不同,所以將要在這個章節說明。
首先在設定 Object 或 Array 這兩種型別的資料時, value 的值建議使用函數,若不是的話,每次這個元素 propery 的初始值都將是同一份 reference,雖然一般可能難以察覺,但確實會在某些時候造成問題。
關於處理陣列時,我們通常會使用到 dom-repeat
這個工具,先看個例子。
myproj-app:
import {html, PolymerElement} from '@polymer/polymer/polymer-element.js'
import '@polymer/polymer/lib/elements/dom-repeat'
import './user-view'class MyprojApp extends PolymerElement {
static get template() {
return html`
<style>
:host {
display: block;
}
#header::after {
display: block;
content: "";
width: 18rem;
height: 1px;
background-color: black;
}
</style>
<h2>Hello myproj-app!</h2>
<div id="container">
<user-view
id="header"
users="[[header]]"
></user-view>
<template is="dom-repeat" items="[[users]]">
<div class="users">
<user-view
users="[[item]]"
></user-view>
</div>
</template>
</div>
`
}
static get properties() {
return {
header: {
type: Object,
value: () => {
return {
name: 'name',
password: 'password'
}
}
},
users: {
type: Array,
value: () => {
return [
{
name: 'amy',
password: 'test1'
},
{
name: 'leo',
password: 'test2'
}
]
}
},
}
}
}
window.customElements.define('myproj-app', MyprojApp)
user-view.js
import {html, PolymerElement} from '@polymer/polymer/polymer-element.js'class UserView extends PolymerElement {
static get template() {
return html`
<style>
:host {
display: block;
}
.users {
display: flex;
flex-direction: row;
}
.name {
width: 5rem;
}
.password {
width: 15rem;
}
</style>
<div class="users">
<div class="name">[[userData.name]]</div>
<div class="password">[[userData.password]]</div>
</div>
`
}
static get properties() {
return {
userData: {
type: Object,
value: () => {
return {
name: '',
password: ''
}
}
},
}
}
}
window.customElements.define('user-view', UserView)
關於 dom-repeat 使用其實還有另一種模式:
<dom-repeat items="[[users]]">
<template>
<div class="users">
<user-view
users="{{item}}"
></user-view>
</div>
</template>
</dom-repeat>
這樣的打法是一樣的。
重點是只要綁定 items
後,之後在 template
內部就能使用 item
存取陣列的內容(其實還有 index 也能使用,就是索引)。
另外還有個工具是 dom-if
與上面的使用方式雷同,大致改成這樣的形式就能使用了:
<template is="dom-if" is="[[prop]]">
...
</template>
上面的內容與上次差不多,是時候該談到一些不同的地方了,也就是更新資料的情況了,也就是說,若直接對物件 property 的成員賦值或增添陣列 property 的內容,恐怕是看不到有任何更動的。
在這個情況要使用特定的函數來進行修改,才會在修改後直接更新 View 的部分。先直接列出這些可能會用到的函數:
存取修改 Property
this.get(path, root)
this.set(path, value, root)
陣列
this.push(path, item1, [..., itemN])
this.pop(path)
this.unshift(path, item1, [..., itemN])
this.shift(path)
this.splice(path, index, removeCount, [item1, ..., itemN])
通知
this.notifyPath(path, value)
this.notifySplices(path, splices)
修改 myproj-app:
import {html, PolymerElement} from '@polymer/polymer/polymer-element.js'
import '@polymer/polymer/lib/elements/dom-repeat'
import './user-view'class MyprojApp extends PolymerElement {
static get template() {
return html`
<style>
:host {
display: block;
}
#header::after {
display: block;
content: "";
width: 18rem;
height: 1px;
background-color: black;
}
</style>
<h2>Hello myproj-app!</h2>
<div id="container">
<button on-click="_createData">create data</button>
<button on-click="_popData">pop data</button>
<br>
<user-view
id="header"
users="[[header]]"
></user-view>
<template is="dom-repeat" items="[[users]]">
<div>
<user-view
users="[[item]]"
></user-view>
</div>
</template>
</div>
`
}
static get properties() {
return {
header: {
type: Object,
value: () => {
return {
name: 'name',
password: 'password'
}
}
},
users: {
type: Array,
value: () => {
return [
{
name: 'amy',
password: 'test1'
},
{
name: 'leo',
password: 'test2'
}
]
}
},
}
}
_popData(e) {
//使用 this.pop
console.log(this.pop('users'))
}
_createData(e) {
let userName = this.idGenerate(this.randomNum(3, 5))
//使用 this.push
this.push('users', {
name: this.idGenerate(this.randomNum(3, 5)),
password: this.passwordGenerate(this.randomNum(7,12))
})
}
idGenerate(length) {
var result = ''
var legalChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_'
for (let i = 0; i < length; i++) {
result += legalChars.charAt(Math.floor(Math.random() * legalChars.length))
}
return result
}
passwordGenerate(length) {
var result = ''
var legalChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._#$%^&*!'
for (let i = 0; i < length; i++) {
result += legalChars.charAt(Math.floor(Math.random() * legalChars.length))
}
return result
}
randomNum(min, max){
return Math.floor(Math.random() * max) + min;
}
}
window.customElements.define('myproj-app', MyprojApp)
在這裡使用了 this.pop
與 this.push
這兩個函數進行更動,基本上這與陣列所提供的 pop
或 push
沒有不同,只是第一個引數要輸入在 properties 下的路徑就是了。其他還有三個有提供的函數 shift
, unshift
, splice
,用法也是一樣。
那麼能不能使用原本的函數呢?
可以的,事實上直接使用陣列的這些函數後, property 是確實有被更改的,只是說,若不是藉由 Polymer 提供的方法來更新時,就需要在期望 view 有更動時手動進行通知才行,舉例來說:
_popData(e) {
console.log(this.users.pop())
this.notifySplices('users')
}
_createData(e) {
this.users.push({
name: this.idGenerate(this.randomNum(3, 5)),
password: this.passwordGenerate(this.randomNum(7,12))
})
}
將上面兩個函數的內容改成這樣效果也會與剛剛一樣,不過你可以試試看把notifySplices 拿掉,這下 view 就不會改變了。
那麼關於 get
, set
的用法要怎麼做呢,舉 set
的例子就夠了:
在上面可以看到在 path 的部分,使用到了索引來存取陣列的元素,而在使用這些用來修改的函數時,path 的部分都可以像這樣使用。
最後通知的部分,只要注意當 property 被更動時使用 notifyPath
,而陣列內容被更動時,要使用notifySplices
就好。