[Polymer 筆記] 4. Properties(二)

Toki Lee
11 min readOct 25, 2019

--

上篇中介紹了一個 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

  1. this.get(path, root)
  2. this.set(path, value, root)

陣列

  1. this.push(path, item1, [..., itemN])
  2. this.pop(path)
  3. this.unshift(path, item1, [..., itemN])
  4. this.shift(path)
  5. this.splice(path, index, removeCount, [item1, ..., itemN])

通知

  1. this.notifyPath(path, value)
  2. 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.popthis.push 這兩個函數進行更動,基本上這與陣列所提供的 poppush 沒有不同,只是第一個引數要輸入在 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就好。

--

--

Toki Lee
Toki Lee

Written by Toki Lee

沒有技術上不可行,只是時間上做不到⋯

No responses yet