mirror of
https://github.com/Tencent/Hippy.git
synced 2026-10-29 06:06:52 +08:00
feat(vue): support to merge styles on root element of child component
This commit is contained in:
@@ -28,7 +28,7 @@ At present, the basic `Universal`, `Type`, `ID`, `Class`, `Grouping` selectors h
|
||||
|
||||
## Scoped & Attribute
|
||||
|
||||
> `2.15.0` support Vue `scoped` style.
|
||||
> `2.15.0` support Vue `scoped` style, `2.15.2` support to merge styles on root element of child component.
|
||||
|
||||
> `2.15.1` support `Attribute` selector and Vue `deep` selector.
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ HippyVue 提供了 `beforeLoadStyle` 的 Vue options 勾子函数,供开发者
|
||||
|
||||
## Scoped & Attribute
|
||||
|
||||
> `2.15.0` 版本增加支持 Vue `scoped` 样式能力
|
||||
> `2.15.0` 版本增加支持 Vue `scoped` 样式能力, `2.15.2` 支持子组件根元素样式合并
|
||||
|
||||
> `2.15.1` 版本增加支持 `Attribute` 选择器和 Vue `deep` 深度选择器
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
v-if="loaded"
|
||||
class="async-com-wrapper"
|
||||
>
|
||||
<AsyncComponentFromLocal />
|
||||
<AsyncComponentFromLocal class="async-component-outer-local" />
|
||||
<AsyncComponentFromHttp />
|
||||
</div>
|
||||
</div>
|
||||
@@ -55,7 +55,11 @@ export default {
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style scoped>
|
||||
.async-component-outer-local {
|
||||
height: 200px;
|
||||
width: 300px;
|
||||
}
|
||||
#demo-dynamicimport {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
|
||||
+4
-6
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div id="asynccomponent">
|
||||
<div class="async-component-local">
|
||||
<text class="async-txt">
|
||||
我是本地异步组件
|
||||
</text>
|
||||
@@ -15,18 +15,16 @@ export default {
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#asynccomponent {
|
||||
<style scoped>
|
||||
.async-component-local {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
height: 200px;
|
||||
width: 300px;
|
||||
background-color: #50ca92;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 10px;
|
||||
background-color: #50ca92;
|
||||
}
|
||||
.async-txt{
|
||||
color: black;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
v-if="loaded"
|
||||
class="async-com-wrapper"
|
||||
>
|
||||
<AsyncComponentFromLocal />
|
||||
<AsyncComponentFromLocal class="async-component-outer-local"/>
|
||||
<AsyncComponentFromHttp />
|
||||
</div>
|
||||
</div>
|
||||
@@ -67,7 +67,11 @@ export default defineComponent({
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style scoped>
|
||||
.async-component-outer-local {
|
||||
height: 200px;
|
||||
width: 300px;
|
||||
}
|
||||
#demo-dynamicimport {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
@@ -92,6 +96,6 @@ export default defineComponent({
|
||||
line-height: 40px;
|
||||
}
|
||||
.async-com-wrapper {
|
||||
marginTop: 20px
|
||||
margin-top: 20px
|
||||
}
|
||||
</style>
|
||||
|
||||
+3
-6
@@ -1,7 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
id="async-component-local"
|
||||
class="local-local"
|
||||
class="async-component-local"
|
||||
>
|
||||
<p class="async-txt">
|
||||
我是本地异步组件
|
||||
@@ -17,15 +16,13 @@ export default defineComponent({
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#async-component-local {
|
||||
<style scoped>
|
||||
.async-component-local {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
height: 200px;
|
||||
width: 300px;
|
||||
background-color: #50ca92;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
@@ -240,10 +240,10 @@ describe('node-ops.ts', () => {
|
||||
it('setScopeId method should work correct', () => {
|
||||
const element = nodeOps.createElement('div');
|
||||
element.setStyleScope('style-scoped-id-1');
|
||||
expect(element.styleScopeId).toEqual('style-scoped-id-1');
|
||||
expect(element.styleScopeId).toEqual(['style-scoped-id-1']);
|
||||
element.setStyleScope({});
|
||||
expect(element.styleScopeId).toEqual('[object Object]');
|
||||
expect(element.styleScopeId).toEqual(['style-scoped-id-1', '[object Object]']);
|
||||
element.setStyleScope(123456);
|
||||
expect(element.styleScopeId).toEqual('123456');
|
||||
expect(element.styleScopeId).toEqual(['style-scoped-id-1', '[object Object]', '123456']);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -579,10 +579,10 @@ describe('runtime/element/hippy-element', () => {
|
||||
it('setStyleScopedId method should work correct', () => {
|
||||
const element = new HippyElement('div');
|
||||
element.setStyleScope('style-scoped-id');
|
||||
expect(element.styleScopeId).toEqual('style-scoped-id');
|
||||
expect(element.styleScopeId).toEqual(['style-scoped-id']);
|
||||
element.setStyleScope({});
|
||||
expect(element.styleScopeId).toEqual('[object Object]');
|
||||
expect(element.styleScopeId).toEqual(['style-scoped-id', '[object Object]']);
|
||||
element.setStyleScope(12345);
|
||||
expect(element.styleScopeId).toEqual('12345');
|
||||
expect(element.styleScopeId).toEqual(['style-scoped-id', '[object Object]', '12345']);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -205,7 +205,7 @@ export class HippyElement extends HippyNode {
|
||||
protected polyFillNativeEvents?: (type: string) => string;
|
||||
|
||||
// style scoped id for element
|
||||
private scopedId?: string | undefined = undefined;
|
||||
private scopedIdList: NeedToTyped[] = [];
|
||||
|
||||
constructor(tagName: string) {
|
||||
super(NodeType.ElementNode);
|
||||
@@ -789,14 +789,17 @@ export class HippyElement extends HippyNode {
|
||||
* @param scopeStyleId - scoped style id
|
||||
*/
|
||||
public setStyleScope(scopeStyleId: NeedToTyped): void {
|
||||
this.scopedId = typeof scopeStyleId !== 'string' ? scopeStyleId.toString() : scopeStyleId;
|
||||
const scopedId = typeof scopeStyleId !== 'string' ? scopeStyleId.toString() : scopeStyleId;
|
||||
if (scopedId && !this.scopedIdList.includes(scopedId)) {
|
||||
this.scopedIdList.push(scopedId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get style scoped id
|
||||
*/
|
||||
public get styleScopeId() {
|
||||
return this.scopedId;
|
||||
return this.scopedIdList;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -360,7 +360,7 @@ const getNodeAttrVal = (node, attribute) => {
|
||||
if (typeof attr !== 'undefined') {
|
||||
return attr;
|
||||
}
|
||||
if (!isNullOrUndefined(node.styleScopeId) && node.styleScopeId === attribute) {
|
||||
if (Array.isArray(node.styleScopeId) && node.styleScopeId.includes(attribute)) {
|
||||
return attribute;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -199,8 +199,8 @@ class ElementNode extends ViewNode {
|
||||
this.id = '';
|
||||
// style attribute in template.
|
||||
this.style = {};
|
||||
// Vue style scope id.
|
||||
this._styleScopeId = undefined;
|
||||
// Vue style scope id list.
|
||||
this.scopeIdList = [];
|
||||
// Class attribute in template.
|
||||
this.classList = new Set(); // Fake DOMTokenLis
|
||||
// Other attributes in template.
|
||||
@@ -441,11 +441,13 @@ class ElementNode extends ViewNode {
|
||||
if (typeof styleScopeId !== 'string') {
|
||||
styleScopeId = styleScopeId.toString();
|
||||
}
|
||||
this._styleScopeId = styleScopeId;
|
||||
if (styleScopeId && !this.scopeIdList.includes(styleScopeId)) {
|
||||
this.scopeIdList.push(styleScopeId);
|
||||
}
|
||||
}
|
||||
|
||||
get styleScopeId() {
|
||||
return this._styleScopeId;
|
||||
return this.scopeIdList;
|
||||
}
|
||||
|
||||
appendChild(childNode) {
|
||||
|
||||
@@ -252,7 +252,7 @@ const getNodeAttrVal = (node, attribute) => {
|
||||
if (typeof attr !== 'undefined') {
|
||||
return attr;
|
||||
}
|
||||
if (!isNullOrUndefined(node.styleScopeId) && node.styleScopeId === attribute) {
|
||||
if (Array.isArray(node.styleScopeId) && node.styleScopeId.includes(attribute)) {
|
||||
return attribute;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
|
||||
import test, { before } from 'ava';
|
||||
@@ -266,5 +286,5 @@ test('setStyleScope test', (t) => {
|
||||
const node = createElement('div');
|
||||
const styleScopeId = 123;
|
||||
t.is(nodeOps.setStyleScope(node, styleScopeId), undefined);
|
||||
t.is(node._styleScopeId, styleScopeId.toString());
|
||||
t.is(node.scopeIdList[0], styleScopeId.toString());
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user