diff --git a/html5/runtime/utils.js b/html5/runtime/utils.js index 9bb69172d9..c2ab10f02d 100644 --- a/html5/runtime/utils.js +++ b/html5/runtime/utils.js @@ -52,3 +52,20 @@ export function base64ToBuffer (base64) { }) return array.buffer } + +/** + * Detect if the param is falsy or empty + * @param {any} any + */ +export function isEmpty (any) { + if (!any || typeof any !== 'object') { + return true + } + + for (const key in any) { + if (Object.prototype.hasOwnProperty.call(any, key)) { + return false + } + } + return true +} diff --git a/html5/runtime/vdom/Element.js b/html5/runtime/vdom/Element.js index 712b925503..5ba05ba05c 100644 --- a/html5/runtime/vdom/Element.js +++ b/html5/runtime/vdom/Element.js @@ -28,7 +28,7 @@ import { moveIndex, removeIndex } from './operation' -import { uniqueId } from '../utils' +import { uniqueId, isEmpty } from '../utils' import { getWeexElement, setElement } from './WeexElement' const DEFAULT_TAG_NAME = 'div' @@ -303,15 +303,23 @@ export default class Element extends Node { * @param {boolean} silent */ setAttrs (batchedAttrs, silent) { - // TODO: validate batched attributes - Object.assign(this.attr, batchedAttrs) - const taskCenter = getTaskCenter(this.docId) - if (!silent && taskCenter) { - taskCenter.send( - 'dom', - { action: 'updateAttrs' }, - [this.ref, batchedAttrs] - ) + if (isEmpty(batchedAttrs)) return + const mutations = {} + for (const key in batchedAttrs) { + if (this.attr[key] !== batchedAttrs[key]) { + this.attr[key] = batchedAttrs[key] + mutations[key] = batchedAttrs[key] + } + } + if (!isEmpty(mutations)) { + const taskCenter = getTaskCenter(this.docId) + if (!silent && taskCenter) { + taskCenter.send( + 'dom', + { action: 'updateAttrs' }, + [this.ref, mutations] + ) + } } } @@ -344,15 +352,23 @@ export default class Element extends Node { * @param {boolean} silent */ setStyles (batchedStyles, silent) { - // TODO: validate batched styles - Object.assign(this.style, batchedStyles) - const taskCenter = getTaskCenter(this.docId) - if (!silent && taskCenter) { - taskCenter.send( - 'dom', - { action: 'updateStyle' }, - [this.ref, batchedStyles] - ) + if (isEmpty(batchedStyles)) return + const mutations = {} + for (const key in batchedStyles) { + if (this.style[key] !== batchedStyles[key]) { + this.style[key] = batchedStyles[key] + mutations[key] = batchedStyles[key] + } + } + if (!isEmpty(mutations)) { + const taskCenter = getTaskCenter(this.docId) + if (!silent && taskCenter) { + taskCenter.send( + 'dom', + { action: 'updateStyle' }, + [this.ref, mutations] + ) + } } } diff --git a/html5/test/unit/runtime/utils.js b/html5/test/unit/runtime/utils.js new file mode 100644 index 0000000000..64807057c7 --- /dev/null +++ b/html5/test/unit/runtime/utils.js @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { expect } from 'chai' +import * as utils from '../../../runtime/utils' + +describe('utils', () => { + it('isEmpty', () => { + expect(utils.isEmpty()).to.be.true + expect(utils.isEmpty(0)).to.be.true + expect(utils.isEmpty(null)).to.be.true + expect(utils.isEmpty(undefined)).to.be.true + expect(utils.isEmpty(false)).to.be.true + expect(utils.isEmpty(true)).to.be.true + expect(utils.isEmpty(NaN)).to.be.true + expect(utils.isEmpty([])).to.be.true + expect(utils.isEmpty({})).to.be.true + expect(utils.isEmpty(Object.create(null))).to.be.true + expect(utils.isEmpty(Object.create({}))).to.be.true + expect(utils.isEmpty(Object.create({ x: '' }))).to.be.true + + expect(utils.isEmpty({ abc: '' })).to.be.false + expect(utils.isEmpty([0])).to.be.false + }) +})