diff --git a/packages/hippy-vue/src/renderer/element-node.js b/packages/hippy-vue/src/renderer/element-node.js index 237c68de8..af6f5422f 100644 --- a/packages/hippy-vue/src/renderer/element-node.js +++ b/packages/hippy-vue/src/renderer/element-node.js @@ -245,18 +245,20 @@ class ElementNode extends ViewNode { setAttribute(key, value, options = {}) { try { + let propKey = key; + let propValue = value; // detect expandable attrs for boolean values // See https://vuejs.org/v2/guide/components-props.html#Passing-a-Boolean - if (typeof (this.attributes[key]) === 'boolean' && value === '') { - value = true; + if (typeof (this.attributes[propKey]) === 'boolean' && propValue === '') { + propValue = true; } - if (key === undefined) { + if (propKey === undefined) { !options.notToNative && updateChild(this); return; } - switch (key) { + switch (propKey) { case 'class': { - const newClassList = new Set(value.split(' ').filter(x => x.trim())); + const newClassList = new Set(propValue.split(' ').filter(x => x.trim())); if (setsAreEqual(this.classList, newClassList)) { return; } @@ -266,10 +268,10 @@ class ElementNode extends ViewNode { return; } case 'id': - if (value === this.id) { + if (propValue === this.id) { return; } - this.id = value; + this.id = propValue; // update current node and child nodes !options.notToNative && updateWithChildren(this); return; @@ -278,51 +280,55 @@ class ElementNode extends ViewNode { case 'value': case 'defaultValue': case 'placeholder': { - if (typeof value !== 'string') { + if (typeof propValue !== 'string') { try { - value = value.toString(); + propValue = propValue.toString(); } catch (err) { - throw new TypeError(`Property ${key} must be string:${err.message}`); + throw new TypeError(`Property ${propKey} must be string:${err.message}`); } } if (!options || !options.textUpdate) { - value = value.trim().replace(/( |Â)/g, ' '); + propValue = propValue.trim().replace(/( |Â)/g, ' '); } - this.attributes[key] = unicodeToChar(value); + propValue = unicodeToChar(propValue); break; } case 'numberOfRows': - this.attributes[key] = value; if (Native.Platform !== 'ios') { return; } break; case 'caretColor': case 'caret-color': - this.attributes['caret-color'] = Native.parseColor(value); + propKey = 'caret-color'; + propValue = Native.parseColor(propValue); break; case 'break-strategy': - this.attributes.breakStrategy = value; + propKey = 'breakStrategy'; break; case 'placeholderTextColor': case 'placeholder-text-color': - this.attributes.placeholderTextColor = Native.parseColor(value); + propKey = 'placeholderTextColor'; + propValue = Native.parseColor(propValue); break; case 'underlineColorAndroid': case 'underline-color-android': - this.attributes.underlineColorAndroid = Native.parseColor(value); + propKey = 'underlineColorAndroid'; + propValue = Native.parseColor(propValue); break; case 'nativeBackgroundAndroid': { - const nativeBackgroundAndroid = value; + const nativeBackgroundAndroid = propValue; if (typeof nativeBackgroundAndroid.color !== 'undefined') { nativeBackgroundAndroid.color = Native.parseColor(nativeBackgroundAndroid.color); } - this.attributes.nativeBackgroundAndroid = nativeBackgroundAndroid; + propKey = 'nativeBackgroundAndroid'; + propValue = nativeBackgroundAndroid; break; } default: - this.attributes[key] = value; } + if (this.attributes[propKey] === propValue) return; + this.attributes[propKey] = propValue; if (typeof this.filterAttribute === 'function') { this.filterAttribute(this.attributes); } diff --git a/packages/hippy-vue/src/renderer/native/__tests__/index.test.js b/packages/hippy-vue/src/renderer/native/__tests__/index.test.js index f5158c1e7..44c4b2617 100644 --- a/packages/hippy-vue/src/renderer/native/__tests__/index.test.js +++ b/packages/hippy-vue/src/renderer/native/__tests__/index.test.js @@ -1,4 +1,22 @@ -// TODO: Add UIManagerModule mock module to verify result correction. +/* + * Tencent is pleased to support the open source community by making + * Hippy available. + * + * Copyright (C) 2017-2022 THL A29 Limited, a Tencent company. + * All rights reserved. + * + * Licensed 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 test, { before } from 'ava'; import { registerBuiltinElements } from '../../../elements'; @@ -383,9 +401,6 @@ test('ul numberOfRows test', (t) => { parentNode.appendChild(childNode2); const nativeLanguage2 = renderToNativeWithChildren(ROOT_VIEW_ID, parentNode); t.is(nativeLanguage2[0].props.numberOfRows, 2); - parentNode.setAttribute('numberOfRows', 10); - const nativeLanguage3 = renderToNativeWithChildren(ROOT_VIEW_ID, parentNode); - t.is(nativeLanguage3[0].props.numberOfRows, 10); }); test('img attributeMaps test --debug mode', (t) => { diff --git a/packages/hippy-vue/src/runtime/modules/attrs.js b/packages/hippy-vue/src/runtime/modules/attrs.js index 66fa7cd5c..1d19c7ea3 100644 --- a/packages/hippy-vue/src/runtime/modules/attrs.js +++ b/packages/hippy-vue/src/runtime/modules/attrs.js @@ -37,8 +37,10 @@ function updateAttrs(oldVNode, vNode) { vNode.data.attrs = attrs; } Object.keys(oldAttrs).forEach((key) => { + const oldPropValue = oldAttrs[key]; const newPropValue = attrs[key]; - if (newPropValue === null || newPropValue === undefined) { + if ((oldPropValue !== null && oldPropValue !== undefined) + && (newPropValue === null || newPropValue === undefined)) { updatePayload[key] = undefined; } }); diff --git a/packages/hippy-vue/src/runtime/modules/style.js b/packages/hippy-vue/src/runtime/modules/style.js index 084d8268e..9611ffb20 100644 --- a/packages/hippy-vue/src/runtime/modules/style.js +++ b/packages/hippy-vue/src/runtime/modules/style.js @@ -58,8 +58,11 @@ function updateStyle(oldVNode, vNode) { const batchedStyles = {}; // Remove the removed styles at first Object.keys(oldStyle).forEach((name) => { + const oldStyleValue = oldStyle[name]; const newStyleValue = style[name]; - if (newStyleValue === undefined || newStyleValue === null) { + if ( + (oldStyleValue !== undefined && oldStyleValue !== null) + && (newStyleValue === undefined || newStyleValue === null)) { batchedStyles[normalize(name)] = undefined; } });