上篇介紹了 Polymer 的 Lifecycle,這篇要介紹另一個 Polymer 的成員函數,如同 properties 和 template 一樣是靜態的成員函數。
還記得在先前談到 properties 的時候,有提到 observer 的用法,不過那是比較簡單的情況,這次談的這個是比較複雜的使用方式。
一個 Observer 大概像是這樣:
// 這是監測陣列 property 變更的方式
static get observers() {
return [
'_usersChanged(users.splices)'
];
}
_usersChanged(changeRecord) {
...
}
那麼主要來說特點是:
- 可以監聽多個 property
- 可以監聽 propert 細節的變化
而這個章節主要就介紹監聽物件與陣列細節的方式。
陣列
還是一樣用之前在 Properties 的例子來修改:
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;
}
.row {
display: flex;
flex-direction: row;
}
</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"
user="[[header]]"
></user-view>
<template is="dom-repeat" items="[[users]]">
<div class="row">
<user-view
user="[[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'
}
]
}
},
}
}
static get observers() {
return [
'_usersChanged(users.splices)'
];
}
_usersChanged(changeRecord) {
if(changeRecord) {
console.log(changeRecord)
}
}
_popData(e) {
this.pop('users')
}
_createData(e) {
let userName = this.idGenerate(this.randomNum(3, 5))
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)
其實就只是增加了 Observer 的部分:
static get observers() {
return [
'_usersChanged(users.splices)'
];
}
_usersChanged(changeRecord) {
if(changeRecord) {
console.log(changeRecord)
}
}
使用 users.splices
可以讓我們監聽 users
的變化。
可以看到當 push 、 pop 或將元素從陣列移出都有監聽到了變化,那麼我們來看裡面提到了什麼。
create的情況
只要打開一看,可以很容易地理解意思, addedCount 說明加了幾個元素,index 說明在哪個位置增加,而 object 就是改變後的狀況摟。
再來 pop 剛剛的內容
一樣這次可以看到 removed 的部分出現內容了,並且就是我們剛刪掉的那個元素。
這樣配合 Observer 我們可以對於細節的變化有更大的掌握。
物件
既然講到陣列了,那麼物件也有類似的使用方式,user-view 稍做個修改。
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;
}
.row {
display: flex;
flex-direction: row;
}
</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"
user="[[header]]"
></user-view>
<template is="dom-repeat" items="[[users]]">
<div class="row">
<user-view
user="[[item]]"
></user-view>
<div>
<button on-click="_reGenerateName">reGenerateName</button>
<button on-click="_reGeneratePass">reGeneratePass</button>
</div>
</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'
}
]
}
},
}
}
static get observers() {
return [
'_usersChanged(users.splices)'
];
}
_usersChanged(changeRecord) {
if(changeRecord) {
console.log(changeRecord)
}
}
_popData(e) {
this.pop('users')
}
_createData(e) {
let userName = this.idGenerate(this.randomNum(3, 5))
this.push('users', {
name: this.idGenerate(this.randomNum(3, 5)),
password: this.passwordGenerate(this.randomNum(7,12))
})
}
_reGenerateName(e) {
this.set(`users.${e.model.itemsIndex}.name`, this.idGenerate(this.randomNum(3, 5)))
}
_reGeneratePass(e) {
this.set(`users.${e.model.itemsIndex}.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)import {html, PolymerElement} from '@polymer/polymer/polymer-element.js'class UserView extends PolymerElement {
static get template() {
return html`
<style>
:host {
display: block;
}
.user {
display: flex;
flex-direction: row;
}
.name {
width: 5rem;
}
.password {
width: 15rem;
}
</style>
<div class="user">
<div class="name">[[user.name]]</div>
<div class="password">[[user.password]]</div>
</div>
`
}
static get properties() {
return {
user: {
type: Object,
value: {
name: '',
password: ''
}
},
}
}
static get observers() {
return [
'_userChange(user.*)'
];
}
_userChange(changed) {
if(changed) {
console.log(changed)
}
}
}
window.customElements.define('user-view', UserView)
在這裡可以看到我們使用了 _userChange(user.*)
這個就跟剛剛陣列的情況類似,這樣可以監聽物件內的細節。
我們重新載入頁面就能看到因初始所建立的 user-view 所產生的變動,可以看到。
那我們對第一個元素依序重新建立一個 name 和 password。
這下子可以看到 path 說明了物件內是哪個位置被更動了,然後更動的值則是 value。
那麼基本上到這邊 Observer的概念就差不多了,當然還有一些變化,不過基本上有這樣的概念就足夠了。