提交 690cdd1b 编写于 作者: fxy060608's avatar fxy060608

feat: add vdom

上级 41114719
...@@ -360,7 +360,7 @@ function useEvent( ...@@ -360,7 +360,7 @@ function useEvent(
if (!state.composing) { if (!state.composing) {
triggerInput( triggerInput(
event, event,
Object.assign( extend(
{ {
value: field.value, value: field.value,
cursor: field.selectionEnd, cursor: field.selectionEnd,
......
...@@ -3085,15 +3085,16 @@ function useEvent(fieldRef, state, trigger, triggerInput, beforeInput) { ...@@ -3085,15 +3085,16 @@ function useEvent(fieldRef, state, trigger, triggerInput, beforeInput) {
}; };
const onInput = function(event, force) { const onInput = function(event, force) {
event.stopPropagation(); event.stopPropagation();
if (typeof beforeInput === "function" && beforeInput(event, state) === false) { let beforeInputDetail = {};
if (typeof beforeInput === "function" && (beforeInputDetail = beforeInput(event, state)) === false) {
return; return;
} }
state.value = field.value; state.value = field.value;
if (!state.composing) { if (!state.composing) {
triggerInput(event, { triggerInput(event, shared.extend({
value: field.value, value: field.value,
cursor: field.selectionEnd cursor: field.selectionEnd
}, force); }, (() => beforeInputDetail instanceof Object ? beforeInputDetail : void 0)()), force);
} }
}; };
const onBlur = function(event) { const onBlur = function(event) {
...@@ -3149,6 +3150,10 @@ const props$n = /* @__PURE__ */ shared.extend({}, props$o, { ...@@ -3149,6 +3150,10 @@ const props$n = /* @__PURE__ */ shared.extend({}, props$o, {
placeholderClass: { placeholderClass: {
type: String, type: String,
default: "input-placeholder" default: "input-placeholder"
},
verifyNumber: {
type: Boolean,
default: false
} }
}); });
var Input = /* @__PURE__ */ defineBuiltInComponent({ var Input = /* @__PURE__ */ defineBuiltInComponent({
...@@ -3180,6 +3185,7 @@ var Input = /* @__PURE__ */ defineBuiltInComponent({ ...@@ -3180,6 +3185,7 @@ var Input = /* @__PURE__ */ defineBuiltInComponent({
return props2.password ? "password" : type2; return props2.password ? "password" : type2;
}); });
const valid = vue.ref(true); const valid = vue.ref(true);
let cachedValue = "";
const rootRef = vue.ref(null); const rootRef = vue.ref(null);
const { const {
fieldRef, fieldRef,
...@@ -3191,6 +3197,17 @@ var Input = /* @__PURE__ */ defineBuiltInComponent({ ...@@ -3191,6 +3197,17 @@ var Input = /* @__PURE__ */ defineBuiltInComponent({
const input = event.target; const input = event.target;
if (NUMBER_TYPES.includes(props2.type)) { if (NUMBER_TYPES.includes(props2.type)) {
valid.value = input.validity && input.validity.valid; valid.value = input.validity && input.validity.valid;
if (!props2.verifyNumber) {
cachedValue = state2.value;
} else {
if (input.validity && !valid.value) {
input.value = cachedValue;
state2.value = input.value;
return false;
} else {
cachedValue = state2.value;
}
}
} }
if (type.value === "number") { if (type.value === "number") {
const maxlength = state2.maxlength; const maxlength = state2.maxlength;
...@@ -3200,6 +3217,11 @@ var Input = /* @__PURE__ */ defineBuiltInComponent({ ...@@ -3200,6 +3217,11 @@ var Input = /* @__PURE__ */ defineBuiltInComponent({
return false; return false;
} }
} }
if (!props2.verifyNumber) {
return {
valid: valid.value
};
}
}); });
const NUMBER_TYPES = ["number", "digit"]; const NUMBER_TYPES = ["number", "digit"];
const step = vue.computed(() => NUMBER_TYPES.includes(props2.type) ? "0.000000000000000001" : ""); const step = vue.computed(() => NUMBER_TYPES.includes(props2.type) ? "0.000000000000000001" : "");
......
...@@ -7989,15 +7989,16 @@ function useEvent(fieldRef, state2, trigger, triggerInput, beforeInput) { ...@@ -7989,15 +7989,16 @@ function useEvent(fieldRef, state2, trigger, triggerInput, beforeInput) {
}; };
const onInput = function(event, force) { const onInput = function(event, force) {
event.stopPropagation(); event.stopPropagation();
if (typeof beforeInput === "function" && beforeInput(event, state2) === false) { let beforeInputDetail = {};
if (typeof beforeInput === "function" && (beforeInputDetail = beforeInput(event, state2)) === false) {
return; return;
} }
state2.value = field.value; state2.value = field.value;
if (!state2.composing) { if (!state2.composing) {
triggerInput(event, { triggerInput(event, extend({
value: field.value, value: field.value,
cursor: field.selectionEnd cursor: field.selectionEnd
}, force); }, (() => beforeInputDetail instanceof Object ? beforeInputDetail : void 0)()), force);
} }
}; };
const onBlur = function(event) { const onBlur = function(event) {
...@@ -8053,6 +8054,10 @@ const props$u = /* @__PURE__ */ extend({}, props$v, { ...@@ -8053,6 +8054,10 @@ const props$u = /* @__PURE__ */ extend({}, props$v, {
placeholderClass: { placeholderClass: {
type: String, type: String,
default: "input-placeholder" default: "input-placeholder"
},
verifyNumber: {
type: Boolean,
default: false
} }
}); });
var Input = /* @__PURE__ */ defineBuiltInComponent({ var Input = /* @__PURE__ */ defineBuiltInComponent({
...@@ -8084,6 +8089,7 @@ var Input = /* @__PURE__ */ defineBuiltInComponent({ ...@@ -8084,6 +8089,7 @@ var Input = /* @__PURE__ */ defineBuiltInComponent({
return props2.password ? "password" : type2; return props2.password ? "password" : type2;
}); });
const valid = ref(true); const valid = ref(true);
let cachedValue = "";
const rootRef = ref(null); const rootRef = ref(null);
const { const {
fieldRef, fieldRef,
...@@ -8095,6 +8101,17 @@ var Input = /* @__PURE__ */ defineBuiltInComponent({ ...@@ -8095,6 +8101,17 @@ var Input = /* @__PURE__ */ defineBuiltInComponent({
const input = event.target; const input = event.target;
if (NUMBER_TYPES.includes(props2.type)) { if (NUMBER_TYPES.includes(props2.type)) {
valid.value = input.validity && input.validity.valid; valid.value = input.validity && input.validity.valid;
if (!props2.verifyNumber) {
cachedValue = state3.value;
} else {
if (input.validity && !valid.value) {
input.value = cachedValue;
state3.value = input.value;
return false;
} else {
cachedValue = state3.value;
}
}
} }
if (type.value === "number") { if (type.value === "number") {
const maxlength = state3.maxlength; const maxlength = state3.maxlength;
...@@ -8104,6 +8121,11 @@ var Input = /* @__PURE__ */ defineBuiltInComponent({ ...@@ -8104,6 +8121,11 @@ var Input = /* @__PURE__ */ defineBuiltInComponent({
return false; return false;
} }
} }
if (!props2.verifyNumber) {
return {
valid: valid.value
};
}
}); });
const NUMBER_TYPES = ["number", "digit"]; const NUMBER_TYPES = ["number", "digit"];
const step = computed(() => NUMBER_TYPES.includes(props2.type) ? "0.000000000000000001" : ""); const step = computed(() => NUMBER_TYPES.includes(props2.type) ? "0.000000000000000001" : "");
......
import { proxyStyle, UniCSSStyleDeclaration } from '../../src/vdom/Style'
describe('vdom', () => {
test('style', () => {
const uniCSSStyle = proxyStyle(new UniCSSStyleDeclaration())
expect(uniCSSStyle.toJSON()).toBe(null)
uniCSSStyle.cssText = 'color:red'
expect(uniCSSStyle.toJSON()).toBe(uniCSSStyle.cssText)
uniCSSStyle.backgroundColor = 'black'
expect(uniCSSStyle.toJSON()).toEqual([
uniCSSStyle.cssText,
{ backgroundColor: uniCSSStyle.backgroundColor },
])
const uniCSSStyle1 = proxyStyle(new UniCSSStyleDeclaration())
uniCSSStyle1.setProperty('--window-top', '0px')
expect(uniCSSStyle1.toJSON()).toEqual({
'--window-top': uniCSSStyle1['--window-top'],
})
})
})
...@@ -215,6 +215,346 @@ function isNativeTag(tag) { ...@@ -215,6 +215,346 @@ function isNativeTag(tag) {
const COMPONENT_SELECTOR_PREFIX = 'uni-'; const COMPONENT_SELECTOR_PREFIX = 'uni-';
const COMPONENT_PREFIX = 'v-' + COMPONENT_SELECTOR_PREFIX; const COMPONENT_PREFIX = 'v-' + COMPONENT_SELECTOR_PREFIX;
class DOMException extends Error {
constructor(message) {
super(message);
this.name = 'DOMException';
}
}
function normalizeEventType(type) {
return `on${shared.capitalize(shared.camelize(type))}`;
}
class UniEvent {
constructor(type, opts) {
this.defaultPrevented = false;
this.timeStamp = Date.now();
this._stop = false;
this._end = false;
this.type = type.toLowerCase();
this.bubbles = !!opts.bubbles;
this.cancelable = !!opts.cancelable;
}
preventDefault() {
this.defaultPrevented = true;
}
stopImmediatePropagation() {
this._end = this._stop = true;
}
stopPropagation() {
this._stop = true;
}
}
class UniEventTarget {
constructor() {
this._listeners = {};
}
dispatchEvent(evt) {
const listeners = this._listeners[evt.type];
if (!listeners) {
return false;
}
const len = listeners.length;
for (let i = 0; i < len; i++) {
listeners[i].call(this, evt);
if (evt._end) {
break;
}
}
return evt.cancelable && evt.defaultPrevented;
}
addEventListener(type, listener, options) {
const isOnce = options && options.once;
if (isOnce) {
const wrapper = function (evt) {
listener.apply(this, [evt]);
this.removeEventListener(type, wrapper, options);
};
return this.addEventListener(type, wrapper, shared.extend(options, { once: false }));
}
(this._listeners[type] || (this._listeners[type] = [])).push(listener);
}
removeEventListener(type, callback, options) {
const listeners = this._listeners[type.toLowerCase()];
if (!listeners) {
return;
}
const index = listeners.indexOf(callback);
if (index > -1) {
listeners.splice(index, 1);
}
}
}
class UniCSSStyleDeclaration {
constructor() {
this._cssText = null;
this._value = null;
}
setProperty(property, value) {
if (value === null || value === '') {
this.removeProperty(property);
}
else {
if (!this._value) {
this._value = {};
}
this._value[property] = value;
}
}
getPropertyValue(property) {
if (!this._value) {
return '';
}
return this._value[property] || '';
}
removeProperty(property) {
if (!this._value) {
return '';
}
const value = this._value[property];
delete this._value[property];
return value;
}
get cssText() {
return this._cssText || '';
}
set cssText(cssText) {
this._cssText = cssText;
}
toJSON() {
const { _cssText, _value } = this;
const hasCssText = _cssText !== null;
const hasValue = _value !== null;
if (hasCssText && hasValue) {
return [_cssText, _value];
}
return hasCssText ? _cssText : _value;
}
}
const STYLE_PROPS = [
'_value',
'_cssText',
'cssText',
'getPropertyValue',
'setProperty',
'removeProperty',
'toJSON',
];
function proxyStyle(uniCssStyle) {
return new Proxy(uniCssStyle, {
get(target, key, receiver) {
if (STYLE_PROPS.indexOf(key) === -1) {
return target.getPropertyValue(key);
}
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
if (STYLE_PROPS.indexOf(key) === -1) {
target.setProperty(key, value);
return true;
}
return Reflect.set(target, key, value, receiver);
},
});
}
const NODE_TYPE_PAGE = 0;
const NODE_TYPE_ELEMENT = 1;
const NODE_TYPE_TEXT = 3;
const NODE_TYPE_COMMENT = 8;
function sibling(node, type) {
const { parentNode } = node;
if (!parentNode) {
return null;
}
const { childNodes } = parentNode;
return childNodes[childNodes.indexOf(node) + (type === 'n' ? 1 : -1)] || null;
}
function removeNode(node) {
const { parentNode } = node;
if (parentNode) {
parentNode.removeChild(node);
}
}
function checkNodeId(node) {
if (!node.nodeId) {
node.nodeId = node.pageNode.genId();
}
}
class UniNode extends UniEventTarget {
constructor(nodeType, nodeName) {
super();
this.pageNode = null;
this.parentNode = null;
this._text = null;
this.nodeType = nodeType;
this.nodeName = nodeName;
this.childNodes = [];
}
get firstChild() {
return this.childNodes[0] || null;
}
get lastChild() {
const { childNodes } = this;
const length = childNodes.length;
return length ? childNodes[length - 1] : null;
}
get nextSibling() {
return sibling(this, 'n');
}
get textContent() {
return this._text || '';
}
set textContent(text) {
this._text = text;
}
get parentElement() {
const { parentNode } = this;
if (parentNode && parentNode.nodeType === NODE_TYPE_ELEMENT) {
return parentNode;
}
return null;
}
get previousSibling() {
return sibling(this, 'p');
}
appendChild(newChild) {
return this.insertBefore(newChild, null);
}
cloneNode(deep) {
const cloned = shared.extend(Object.create(Object.getPrototypeOf(this)), this);
const { attributes } = cloned;
if (attributes) {
cloned.attributes = shared.extend({}, attributes);
}
if (deep) {
cloned.childNodes = cloned.childNodes.map((childNode) => childNode.cloneNode(true));
}
return cloned;
}
insertBefore(newChild, refChild) {
removeNode(newChild);
newChild.pageNode = this.pageNode;
newChild.parentNode = this;
checkNodeId(newChild);
const { childNodes } = this;
if (refChild) {
const index = childNodes.indexOf(refChild);
if (index === -1) {
throw new DOMException(`Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.`);
}
childNodes.splice(childNodes.indexOf(refChild), 0, newChild);
}
else {
childNodes.push(newChild);
}
return newChild;
}
removeChild(oldChild) {
const { childNodes } = this;
const index = childNodes.indexOf(oldChild);
if (index === -1) {
throw new DOMException(`Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.`);
}
oldChild.parentNode = null;
childNodes.splice(index, 1);
return oldChild;
}
}
class UniBaseNode extends UniNode {
constructor(nodeType, nodeName) {
super(nodeType, nodeName);
this.attributes = Object.create(null);
this._html = null;
this.style = proxyStyle(new UniCSSStyleDeclaration());
}
get className() {
return (this.attributes['class'] || '');
}
set className(val) {
this.setAttribute('class', val);
}
get innerHTML() {
return '';
}
set innerHTML(html) {
this._html = html;
}
addEventListener(type, listener, options) {
super.addEventListener(type, listener, options);
const normalized = normalizeEventType(type);
if (!this.attributes[normalized]) {
this.setAttribute(normalized, 1);
}
}
removeEventListener(type, callback, options) {
super.removeEventListener(type, callback, options);
const normalized = normalizeEventType(type);
if (this.attributes[normalized]) {
this.removeAttribute(normalized);
}
}
getAttribute(qualifiedName) {
return this.attributes[qualifiedName];
}
removeAttribute(qualifiedName) {
delete this.attributes[qualifiedName];
}
setAttribute(qualifiedName, value) {
this.attributes[qualifiedName] = value;
}
toJSON() {
const res = {
i: this.nodeId,
n: this.nodeName,
a: this.attributes,
s: this.style.toJSON(),
};
if (this._text !== null) {
res.t = this._text;
}
return res;
}
}
class UniCommentNode extends UniNode {
constructor(text) {
super(NODE_TYPE_COMMENT, '#comment');
this._text = text;
}
}
class UniElement extends UniBaseNode {
constructor(nodeName) {
super(NODE_TYPE_ELEMENT, nodeName.toUpperCase());
this.tagName = this.nodeName;
}
}
class UniInputElement extends UniElement {
get value() {
return this.getAttribute('value');
}
set value(val) {
this.setAttribute('value', val);
}
}
class UniTextAreaElement extends UniInputElement {
}
class UniTextNode extends UniBaseNode {
constructor(text) {
super(NODE_TYPE_TEXT, '#text');
this._text = text;
}
get nodeValue() {
return this._text || '';
}
set nodeValue(text) {
this._text = text;
}
}
function getLen(str = '') { function getLen(str = '') {
return ('' + str).replace(/[^\x00-\xff]/g, '**').length; return ('' + str).replace(/[^\x00-\xff]/g, '**').length;
} }
...@@ -398,6 +738,10 @@ exports.COMPONENT_NAME_PREFIX = COMPONENT_NAME_PREFIX; ...@@ -398,6 +738,10 @@ exports.COMPONENT_NAME_PREFIX = COMPONENT_NAME_PREFIX;
exports.COMPONENT_PREFIX = COMPONENT_PREFIX; exports.COMPONENT_PREFIX = COMPONENT_PREFIX;
exports.COMPONENT_SELECTOR_PREFIX = COMPONENT_SELECTOR_PREFIX; exports.COMPONENT_SELECTOR_PREFIX = COMPONENT_SELECTOR_PREFIX;
exports.NAVBAR_HEIGHT = NAVBAR_HEIGHT; exports.NAVBAR_HEIGHT = NAVBAR_HEIGHT;
exports.NODE_TYPE_COMMENT = NODE_TYPE_COMMENT;
exports.NODE_TYPE_ELEMENT = NODE_TYPE_ELEMENT;
exports.NODE_TYPE_PAGE = NODE_TYPE_PAGE;
exports.NODE_TYPE_TEXT = NODE_TYPE_TEXT;
exports.ON_REACH_BOTTOM_DISTANCE = ON_REACH_BOTTOM_DISTANCE; exports.ON_REACH_BOTTOM_DISTANCE = ON_REACH_BOTTOM_DISTANCE;
exports.PLUS_RE = PLUS_RE; exports.PLUS_RE = PLUS_RE;
exports.PRIMARY_COLOR = PRIMARY_COLOR; exports.PRIMARY_COLOR = PRIMARY_COLOR;
...@@ -409,6 +753,14 @@ exports.UNI_SSR_DATA = UNI_SSR_DATA; ...@@ -409,6 +753,14 @@ exports.UNI_SSR_DATA = UNI_SSR_DATA;
exports.UNI_SSR_GLOBAL_DATA = UNI_SSR_GLOBAL_DATA; exports.UNI_SSR_GLOBAL_DATA = UNI_SSR_GLOBAL_DATA;
exports.UNI_SSR_STORE = UNI_SSR_STORE; exports.UNI_SSR_STORE = UNI_SSR_STORE;
exports.UNI_SSR_TITLE = UNI_SSR_TITLE; exports.UNI_SSR_TITLE = UNI_SSR_TITLE;
exports.UniBaseNode = UniBaseNode;
exports.UniCommentNode = UniCommentNode;
exports.UniElement = UniElement;
exports.UniEvent = UniEvent;
exports.UniInputElement = UniInputElement;
exports.UniNode = UniNode;
exports.UniTextAreaElement = UniTextAreaElement;
exports.UniTextNode = UniTextNode;
exports.addFont = addFont; exports.addFont = addFont;
exports.callOptions = callOptions; exports.callOptions = callOptions;
exports.createRpx2Unit = createRpx2Unit; exports.createRpx2Unit = createRpx2Unit;
......
...@@ -66,8 +66,22 @@ export declare function isCustomElement(tag: string): boolean; ...@@ -66,8 +66,22 @@ export declare function isCustomElement(tag: string): boolean;
export declare function isNativeTag(tag: string): boolean; export declare function isNativeTag(tag: string): boolean;
export declare interface IUniPageNode {
pageId: number;
genId: () => number;
push: (...args: any[]) => void;
}
export declare const NAVBAR_HEIGHT = 44; export declare const NAVBAR_HEIGHT = 44;
export declare const NODE_TYPE_COMMENT = 8;
export declare const NODE_TYPE_ELEMENT = 1;
export declare const NODE_TYPE_PAGE = 0;
export declare const NODE_TYPE_TEXT = 3;
export declare function normalizeDataset(el: Element): any; export declare function normalizeDataset(el: Element): any;
export declare function normalizeTarget(el: HTMLElement): { export declare function normalizeTarget(el: HTMLElement): {
...@@ -133,6 +147,137 @@ export declare const UNI_SSR_STORE = "store"; ...@@ -133,6 +147,137 @@ export declare const UNI_SSR_STORE = "store";
export declare const UNI_SSR_TITLE = "title"; export declare const UNI_SSR_TITLE = "title";
export declare class UniBaseNode extends UniNode {
attributes: Record<string, unknown>;
style: UniCSSStyleDeclaration;
protected _html: string | null;
constructor(nodeType: UniNodeType, nodeName: string);
get className(): string;
set className(val: string);
get innerHTML(): string;
set innerHTML(html: string);
addEventListener(type: string, listener: UniEventListener, options?: AddEventListenerOptions): void;
removeEventListener(type: string, callback: UniEventListener, options?: EventListenerOptions): void;
getAttribute(qualifiedName: string): unknown;
removeAttribute(qualifiedName: string): void;
setAttribute(qualifiedName: string, value: unknown): void;
toJSON(): UniNodeJSON;
}
export declare class UniCommentNode extends UniNode {
constructor(text: string);
}
declare class UniCSSStyleDeclaration {
[name: string]: string | unknown;
private _cssText;
private _value;
setProperty(property: string, value: string | null): void;
getPropertyValue(property: string): string | string[];
removeProperty(property: string): string;
get cssText(): string;
set cssText(cssText: string);
toJSON(): UniCSSStyleDeclarationJSON;
}
declare type UniCSSStyleDeclarationJSON = string | null | Record<string, string | string[]> | [string, Record<string, string | string[]>];
export declare class UniElement extends UniBaseNode {
tagName: string;
constructor(nodeName: string);
}
export declare class UniEvent {
type: string;
bubbles: boolean;
cancelable: boolean;
defaultPrevented: boolean;
timeStamp: number;
_stop: boolean;
_end: boolean;
constructor(type: string, opts: UniEventOptions);
preventDefault(): void;
stopImmediatePropagation(): void;
stopPropagation(): void;
}
export declare interface UniEventListener {
(evt: UniEvent): void;
}
declare interface UniEventOptions {
bubbles: boolean;
cancelable: boolean;
}
declare class UniEventTarget {
private _listeners;
dispatchEvent(evt: UniEvent): boolean;
addEventListener(type: string, listener: UniEventListener, options?: AddEventListenerOptions): void;
removeEventListener(type: string, callback: UniEventListener, options?: EventListenerOptions): void;
}
export declare class UniInputElement extends UniElement {
get value(): string | number;
set value(val: string | number);
}
export declare class UniNode extends UniEventTarget {
nodeId?: number;
nodeType: UniNodeType;
nodeName: string;
childNodes: UniNode[];
pageNode: IUniPageNode | null;
parentNode: UniNode | null;
protected _text: string | null;
constructor(nodeType: UniNodeType, nodeName: string);
get firstChild(): UniNode | null;
get lastChild(): UniNode | null;
get nextSibling(): UniNode | null;
get textContent(): string;
set textContent(text: string);
get parentElement(): UniElement | null;
get previousSibling(): UniNode | null;
appendChild<T extends UniNode>(newChild: T): T;
cloneNode(deep?: boolean): UniNode;
insertBefore<T extends UniNode>(newChild: T, refChild: UniNode | null): T;
removeChild<T extends UniNode>(oldChild: T): T;
}
export declare interface UniNodeJSON {
/**
* nodeId
*/
i: number;
/**
* nodeName
*/
n: string;
/**
* attributes
*/
a: Record<string, unknown>;
/**
* style
*/
s: UniCSSStyleDeclarationJSON;
/**
* text
*/
t?: string;
}
declare type UniNodeType = typeof NODE_TYPE_PAGE | typeof NODE_TYPE_ELEMENT | typeof NODE_TYPE_TEXT | typeof NODE_TYPE_COMMENT;
export declare class UniTextAreaElement extends UniInputElement {
}
export declare class UniTextNode extends UniBaseNode {
constructor(text: string);
get nodeValue(): string;
set nodeValue(text: string);
}
export declare function updateElementStyle(element: HTMLElement, styles: Partial<CSSStyleDeclaration>): void; export declare function updateElementStyle(element: HTMLElement, styles: Partial<CSSStyleDeclaration>): void;
export { } export { }
import { camelize, extend, isString, isHTMLTag, isSVGTag, isPlainObject, isArray } from '@vue/shared'; import { camelize, extend, isString, isHTMLTag, isSVGTag, capitalize, isPlainObject, isArray } from '@vue/shared';
function formatKey(key) { function formatKey(key) {
return camelize(key.substring(5)); return camelize(key.substring(5));
...@@ -211,6 +211,346 @@ function isNativeTag(tag) { ...@@ -211,6 +211,346 @@ function isNativeTag(tag) {
const COMPONENT_SELECTOR_PREFIX = 'uni-'; const COMPONENT_SELECTOR_PREFIX = 'uni-';
const COMPONENT_PREFIX = 'v-' + COMPONENT_SELECTOR_PREFIX; const COMPONENT_PREFIX = 'v-' + COMPONENT_SELECTOR_PREFIX;
class DOMException extends Error {
constructor(message) {
super(message);
this.name = 'DOMException';
}
}
function normalizeEventType(type) {
return `on${capitalize(camelize(type))}`;
}
class UniEvent {
constructor(type, opts) {
this.defaultPrevented = false;
this.timeStamp = Date.now();
this._stop = false;
this._end = false;
this.type = type.toLowerCase();
this.bubbles = !!opts.bubbles;
this.cancelable = !!opts.cancelable;
}
preventDefault() {
this.defaultPrevented = true;
}
stopImmediatePropagation() {
this._end = this._stop = true;
}
stopPropagation() {
this._stop = true;
}
}
class UniEventTarget {
constructor() {
this._listeners = {};
}
dispatchEvent(evt) {
const listeners = this._listeners[evt.type];
if (!listeners) {
return false;
}
const len = listeners.length;
for (let i = 0; i < len; i++) {
listeners[i].call(this, evt);
if (evt._end) {
break;
}
}
return evt.cancelable && evt.defaultPrevented;
}
addEventListener(type, listener, options) {
const isOnce = options && options.once;
if (isOnce) {
const wrapper = function (evt) {
listener.apply(this, [evt]);
this.removeEventListener(type, wrapper, options);
};
return this.addEventListener(type, wrapper, extend(options, { once: false }));
}
(this._listeners[type] || (this._listeners[type] = [])).push(listener);
}
removeEventListener(type, callback, options) {
const listeners = this._listeners[type.toLowerCase()];
if (!listeners) {
return;
}
const index = listeners.indexOf(callback);
if (index > -1) {
listeners.splice(index, 1);
}
}
}
class UniCSSStyleDeclaration {
constructor() {
this._cssText = null;
this._value = null;
}
setProperty(property, value) {
if (value === null || value === '') {
this.removeProperty(property);
}
else {
if (!this._value) {
this._value = {};
}
this._value[property] = value;
}
}
getPropertyValue(property) {
if (!this._value) {
return '';
}
return this._value[property] || '';
}
removeProperty(property) {
if (!this._value) {
return '';
}
const value = this._value[property];
delete this._value[property];
return value;
}
get cssText() {
return this._cssText || '';
}
set cssText(cssText) {
this._cssText = cssText;
}
toJSON() {
const { _cssText, _value } = this;
const hasCssText = _cssText !== null;
const hasValue = _value !== null;
if (hasCssText && hasValue) {
return [_cssText, _value];
}
return hasCssText ? _cssText : _value;
}
}
const STYLE_PROPS = [
'_value',
'_cssText',
'cssText',
'getPropertyValue',
'setProperty',
'removeProperty',
'toJSON',
];
function proxyStyle(uniCssStyle) {
return new Proxy(uniCssStyle, {
get(target, key, receiver) {
if (STYLE_PROPS.indexOf(key) === -1) {
return target.getPropertyValue(key);
}
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
if (STYLE_PROPS.indexOf(key) === -1) {
target.setProperty(key, value);
return true;
}
return Reflect.set(target, key, value, receiver);
},
});
}
const NODE_TYPE_PAGE = 0;
const NODE_TYPE_ELEMENT = 1;
const NODE_TYPE_TEXT = 3;
const NODE_TYPE_COMMENT = 8;
function sibling(node, type) {
const { parentNode } = node;
if (!parentNode) {
return null;
}
const { childNodes } = parentNode;
return childNodes[childNodes.indexOf(node) + (type === 'n' ? 1 : -1)] || null;
}
function removeNode(node) {
const { parentNode } = node;
if (parentNode) {
parentNode.removeChild(node);
}
}
function checkNodeId(node) {
if (!node.nodeId) {
node.nodeId = node.pageNode.genId();
}
}
class UniNode extends UniEventTarget {
constructor(nodeType, nodeName) {
super();
this.pageNode = null;
this.parentNode = null;
this._text = null;
this.nodeType = nodeType;
this.nodeName = nodeName;
this.childNodes = [];
}
get firstChild() {
return this.childNodes[0] || null;
}
get lastChild() {
const { childNodes } = this;
const length = childNodes.length;
return length ? childNodes[length - 1] : null;
}
get nextSibling() {
return sibling(this, 'n');
}
get textContent() {
return this._text || '';
}
set textContent(text) {
this._text = text;
}
get parentElement() {
const { parentNode } = this;
if (parentNode && parentNode.nodeType === NODE_TYPE_ELEMENT) {
return parentNode;
}
return null;
}
get previousSibling() {
return sibling(this, 'p');
}
appendChild(newChild) {
return this.insertBefore(newChild, null);
}
cloneNode(deep) {
const cloned = extend(Object.create(Object.getPrototypeOf(this)), this);
const { attributes } = cloned;
if (attributes) {
cloned.attributes = extend({}, attributes);
}
if (deep) {
cloned.childNodes = cloned.childNodes.map((childNode) => childNode.cloneNode(true));
}
return cloned;
}
insertBefore(newChild, refChild) {
removeNode(newChild);
newChild.pageNode = this.pageNode;
newChild.parentNode = this;
checkNodeId(newChild);
const { childNodes } = this;
if (refChild) {
const index = childNodes.indexOf(refChild);
if (index === -1) {
throw new DOMException(`Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.`);
}
childNodes.splice(childNodes.indexOf(refChild), 0, newChild);
}
else {
childNodes.push(newChild);
}
return newChild;
}
removeChild(oldChild) {
const { childNodes } = this;
const index = childNodes.indexOf(oldChild);
if (index === -1) {
throw new DOMException(`Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.`);
}
oldChild.parentNode = null;
childNodes.splice(index, 1);
return oldChild;
}
}
class UniBaseNode extends UniNode {
constructor(nodeType, nodeName) {
super(nodeType, nodeName);
this.attributes = Object.create(null);
this._html = null;
this.style = proxyStyle(new UniCSSStyleDeclaration());
}
get className() {
return (this.attributes['class'] || '');
}
set className(val) {
this.setAttribute('class', val);
}
get innerHTML() {
return '';
}
set innerHTML(html) {
this._html = html;
}
addEventListener(type, listener, options) {
super.addEventListener(type, listener, options);
const normalized = normalizeEventType(type);
if (!this.attributes[normalized]) {
this.setAttribute(normalized, 1);
}
}
removeEventListener(type, callback, options) {
super.removeEventListener(type, callback, options);
const normalized = normalizeEventType(type);
if (this.attributes[normalized]) {
this.removeAttribute(normalized);
}
}
getAttribute(qualifiedName) {
return this.attributes[qualifiedName];
}
removeAttribute(qualifiedName) {
delete this.attributes[qualifiedName];
}
setAttribute(qualifiedName, value) {
this.attributes[qualifiedName] = value;
}
toJSON() {
const res = {
i: this.nodeId,
n: this.nodeName,
a: this.attributes,
s: this.style.toJSON(),
};
if (this._text !== null) {
res.t = this._text;
}
return res;
}
}
class UniCommentNode extends UniNode {
constructor(text) {
super(NODE_TYPE_COMMENT, '#comment');
this._text = text;
}
}
class UniElement extends UniBaseNode {
constructor(nodeName) {
super(NODE_TYPE_ELEMENT, nodeName.toUpperCase());
this.tagName = this.nodeName;
}
}
class UniInputElement extends UniElement {
get value() {
return this.getAttribute('value');
}
set value(val) {
this.setAttribute('value', val);
}
}
class UniTextAreaElement extends UniInputElement {
}
class UniTextNode extends UniBaseNode {
constructor(text) {
super(NODE_TYPE_TEXT, '#text');
this._text = text;
}
get nodeValue() {
return this._text || '';
}
set nodeValue(text) {
this._text = text;
}
}
function getLen(str = '') { function getLen(str = '') {
return ('' + str).replace(/[^\x00-\xff]/g, '**').length; return ('' + str).replace(/[^\x00-\xff]/g, '**').length;
} }
...@@ -389,4 +729,4 @@ function getEnvLocale() { ...@@ -389,4 +729,4 @@ function getEnvLocale() {
return (lang && lang.replace(/[.:].*/, '')) || 'en'; return (lang && lang.replace(/[.:].*/, '')) || 'en';
} }
export { BUILT_IN_TAGS, COMPONENT_NAME_PREFIX, COMPONENT_PREFIX, COMPONENT_SELECTOR_PREFIX, NAVBAR_HEIGHT, ON_REACH_BOTTOM_DISTANCE, PLUS_RE, PRIMARY_COLOR, RESPONSIVE_MIN_WIDTH, TABBAR_HEIGHT, TAGS, UNI_SSR, UNI_SSR_DATA, UNI_SSR_GLOBAL_DATA, UNI_SSR_STORE, UNI_SSR_TITLE, addFont, callOptions, createRpx2Unit, debounce, decode, decodedQuery, defaultRpx2Unit, formatDateTime, getCustomDataset, getEnvLocale, getLen, initCustomDataset, invokeArrayFns, isBuiltInComponent, isCustomElement, isNativeTag, normalizeDataset, normalizeTarget, once, parseQuery, passive, plusReady, removeLeadingSlash, sanitise, scrollTo, stringifyQuery, updateElementStyle }; export { BUILT_IN_TAGS, COMPONENT_NAME_PREFIX, COMPONENT_PREFIX, COMPONENT_SELECTOR_PREFIX, NAVBAR_HEIGHT, NODE_TYPE_COMMENT, NODE_TYPE_ELEMENT, NODE_TYPE_PAGE, NODE_TYPE_TEXT, ON_REACH_BOTTOM_DISTANCE, PLUS_RE, PRIMARY_COLOR, RESPONSIVE_MIN_WIDTH, TABBAR_HEIGHT, TAGS, UNI_SSR, UNI_SSR_DATA, UNI_SSR_GLOBAL_DATA, UNI_SSR_STORE, UNI_SSR_TITLE, UniBaseNode, UniCommentNode, UniElement, UniEvent, UniInputElement, UniNode, UniTextAreaElement, UniTextNode, addFont, callOptions, createRpx2Unit, debounce, decode, decodedQuery, defaultRpx2Unit, formatDateTime, getCustomDataset, getEnvLocale, getLen, initCustomDataset, invokeArrayFns, isBuiltInComponent, isCustomElement, isNativeTag, normalizeDataset, normalizeTarget, once, parseQuery, passive, plusReady, removeLeadingSlash, sanitise, scrollTo, stringifyQuery, updateElementStyle };
export * from './dom' export * from './dom'
export * from './plus' export * from './plus'
export * from './tags' export * from './tags'
export * from './vdom'
export * from './utils' export * from './utils'
export * from './query' export * from './query'
export * from './debounce' export * from './debounce'
......
import { NODE_TYPE_COMMENT, UniNode } from './Node'
export class UniCommentNode extends UniNode {
constructor(text: string) {
super(NODE_TYPE_COMMENT, '#comment')
this._text = text
}
}
export class DOMException extends Error {
constructor(message?: string) {
super(message)
this.name = 'DOMException'
}
}
import { NODE_TYPE_ELEMENT, UniBaseNode } from './Node'
export class UniElement extends UniBaseNode {
tagName: string
constructor(nodeName: string) {
super(NODE_TYPE_ELEMENT, nodeName.toUpperCase())
this.tagName = this.nodeName
}
}
export class UniInputElement extends UniElement {
get value() {
return this.getAttribute('value') as string | number
}
set value(val: string | number) {
this.setAttribute('value', val)
}
}
export class UniTextAreaElement extends UniInputElement {}
import { extend, capitalize, camelize } from '@vue/shared'
import { UniElement } from './Element'
export function normalizeEventType(type: string) {
return `on${capitalize(camelize(type))}`
}
export interface UniEventListener {
(evt: UniEvent): void
}
interface UniEventOptions {
bubbles: boolean
cancelable: boolean
}
export class UniEvent {
type: string
bubbles: boolean
cancelable: boolean
defaultPrevented: boolean = false
timeStamp = Date.now()
_stop: boolean = false
_end: boolean = false
constructor(type: string, opts: UniEventOptions) {
this.type = type.toLowerCase()
this.bubbles = !!opts.bubbles
this.cancelable = !!opts.cancelable
}
preventDefault(): void {
this.defaultPrevented = true
}
stopImmediatePropagation(): void {
this._end = this._stop = true
}
stopPropagation(): void {
this._stop = true
}
}
export class UniEventTarget {
private _listeners: Record<string, UniEventListener[]> = {}
dispatchEvent(evt: UniEvent): boolean {
const listeners = this._listeners[evt.type]
if (!listeners) {
return false
}
const len = listeners.length
for (let i = 0; i < len; i++) {
listeners[i].call(this, evt)
if (evt._end) {
break
}
}
return evt.cancelable && evt.defaultPrevented
}
addEventListener(
type: string,
listener: UniEventListener,
options?: AddEventListenerOptions
): void {
const isOnce = options && options.once
if (isOnce) {
const wrapper = function (this: UniElement, evt: UniEvent) {
listener.apply(this, [evt])
this.removeEventListener(type, wrapper, options)
}
return this.addEventListener(
type,
wrapper,
extend(options, { once: false })
)
}
;(this._listeners[type] || (this._listeners[type] = [])).push(listener)
}
removeEventListener(
type: string,
callback: UniEventListener,
options?: EventListenerOptions
): void {
const listeners = this._listeners[type.toLowerCase()]
if (!listeners) {
return
}
const index = listeners.indexOf(callback)
if (index > -1) {
listeners.splice(index, 1)
}
}
}
import { extend } from '@vue/shared'
import { UniElement } from './Element'
import { DOMException } from './DOMException'
import { normalizeEventType, UniEventListener, UniEventTarget } from './Event'
import {
proxyStyle,
UniCSSStyleDeclaration,
UniCSSStyleDeclarationJSON,
} from './Style'
export const NODE_TYPE_PAGE = 0
export const NODE_TYPE_ELEMENT = 1
export const NODE_TYPE_TEXT = 3
export const NODE_TYPE_COMMENT = 8
type UniNodeType =
| typeof NODE_TYPE_PAGE
| typeof NODE_TYPE_ELEMENT
| typeof NODE_TYPE_TEXT
| typeof NODE_TYPE_COMMENT
function sibling(node: UniNode, type: 'n' | 'p') {
const { parentNode } = node
if (!parentNode) {
return null
}
const { childNodes } = parentNode
return childNodes[childNodes.indexOf(node) + (type === 'n' ? 1 : -1)] || null
}
function removeNode(node: UniNode) {
const { parentNode } = node
if (parentNode) {
parentNode.removeChild(node)
}
}
function checkNodeId(node: UniNode) {
if (!node.nodeId) {
node.nodeId = node.pageNode!.genId()
}
}
export interface IUniPageNode {
pageId: number
genId: () => number
push: (...args: any[]) => void
}
export class UniNode extends UniEventTarget {
nodeId?: number
nodeType: UniNodeType
nodeName: string
childNodes: UniNode[]
pageNode: IUniPageNode | null = null
parentNode: UniNode | null = null
protected _text: string | null = null
constructor(nodeType: UniNodeType, nodeName: string) {
super()
this.nodeType = nodeType
this.nodeName = nodeName
this.childNodes = []
}
get firstChild(): UniNode | null {
return this.childNodes[0] || null
}
get lastChild(): UniNode | null {
const { childNodes } = this
const length = childNodes.length
return length ? childNodes[length - 1] : null
}
get nextSibling(): UniNode | null {
return sibling(this, 'n')
}
get textContent() {
return this._text || ''
}
set textContent(text: string) {
this._text = text
}
get parentElement(): UniElement | null {
const { parentNode } = this
if (parentNode && parentNode.nodeType === NODE_TYPE_ELEMENT) {
return parentNode as unknown as UniElement
}
return null
}
get previousSibling(): UniNode | null {
return sibling(this, 'p')
}
appendChild<T extends UniNode>(newChild: T): T {
return this.insertBefore(newChild, null)
}
cloneNode(deep?: boolean): UniNode {
const cloned = extend(
Object.create(Object.getPrototypeOf(this)),
this
) as UniNode
const { attributes } = cloned as unknown as UniElement
if (attributes) {
;(cloned as unknown as UniElement).attributes = extend({}, attributes)
}
if (deep) {
cloned.childNodes = cloned.childNodes.map((childNode) =>
childNode.cloneNode(true)
)
}
return cloned
}
insertBefore<T extends UniNode>(newChild: T, refChild: UniNode | null): T {
removeNode(newChild)
newChild.pageNode = this.pageNode
newChild.parentNode = this
checkNodeId(newChild)
const { childNodes } = this
if (refChild) {
const index = childNodes.indexOf(refChild)
if (index === -1) {
throw new DOMException(
`Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.`
)
}
childNodes.splice(childNodes.indexOf(refChild), 0, newChild)
} else {
childNodes.push(newChild)
}
return newChild
}
removeChild<T extends UniNode>(oldChild: T): T {
const { childNodes } = this
const index = childNodes.indexOf(oldChild)
if (index === -1) {
throw new DOMException(
`Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.`
)
}
oldChild.parentNode = null
childNodes.splice(index, 1)
return oldChild
}
}
export interface UniNodeJSON {
/**
* nodeId
*/
i: number
/**
* nodeName
*/
n: string
/**
* attributes
*/
a: Record<string, unknown>
/**
* style
*/
s: UniCSSStyleDeclarationJSON
/**
* text
*/
t?: string
}
export class UniBaseNode extends UniNode {
attributes: Record<string, unknown> = Object.create(null)
style: UniCSSStyleDeclaration
protected _html: string | null = null
constructor(nodeType: UniNodeType, nodeName: string) {
super(nodeType, nodeName)
this.style = proxyStyle(new UniCSSStyleDeclaration())
}
get className() {
return (this.attributes['class'] || '') as string
}
set className(val: string) {
this.setAttribute('class', val)
}
get innerHTML() {
return ''
}
set innerHTML(html: string) {
this._html = html
}
addEventListener(
type: string,
listener: UniEventListener,
options?: AddEventListenerOptions
) {
super.addEventListener(type, listener, options)
const normalized = normalizeEventType(type)
if (!this.attributes[normalized]) {
this.setAttribute(normalized, 1)
}
}
removeEventListener(
type: string,
callback: UniEventListener,
options?: EventListenerOptions
) {
super.removeEventListener(type, callback, options)
const normalized = normalizeEventType(type)
if (this.attributes[normalized]) {
this.removeAttribute(normalized)
}
}
getAttribute(qualifiedName: string) {
return this.attributes[qualifiedName]
}
removeAttribute(qualifiedName: string): void {
delete this.attributes[qualifiedName]
}
setAttribute(qualifiedName: string, value: unknown): void {
this.attributes[qualifiedName] = value
}
toJSON() {
const res: UniNodeJSON = {
i: this.nodeId!,
n: this.nodeName,
a: this.attributes,
s: this.style.toJSON(),
}
if (this._text !== null) {
res.t = this._text
}
return res
}
}
export type UniCSSStyleDeclarationJSON =
| string
| null
| Record<string, string | string[]>
| [string, Record<string, string | string[]>]
export class UniCSSStyleDeclaration {
[name: string]: string | unknown
private _cssText: string | null = null
private _value: Record<string, string | string[]> | null = null
setProperty(property: string, value: string | null): void {
if (value === null || value === '') {
this.removeProperty(property)
} else {
if (!this._value) {
this._value = {}
}
this._value[property] = value
}
}
getPropertyValue(property: string) {
if (!this._value) {
return ''
}
return this._value[property] || ''
}
removeProperty(property: string): string {
if (!this._value) {
return ''
}
const value = this._value[property]
delete this._value[property]
return value as string
}
get cssText() {
return this._cssText || ''
}
set cssText(cssText: string) {
this._cssText = cssText
}
toJSON(): UniCSSStyleDeclarationJSON {
const { _cssText, _value } = this
const hasCssText = _cssText !== null
const hasValue = _value !== null
if (hasCssText && hasValue) {
return [_cssText!, _value!]
}
return hasCssText ? _cssText : _value
}
}
const STYLE_PROPS = [
'_value',
'_cssText',
'cssText',
'getPropertyValue',
'setProperty',
'removeProperty',
'toJSON',
]
export function proxyStyle(uniCssStyle: UniCSSStyleDeclaration) {
return new Proxy(uniCssStyle, {
get(target, key, receiver) {
if (STYLE_PROPS.indexOf(key as string) === -1) {
return target.getPropertyValue(key as string)
}
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
if (STYLE_PROPS.indexOf(key as string) === -1) {
target.setProperty(key as string, value)
return true
}
return Reflect.set(target, key, value, receiver)
},
})
}
import { NODE_TYPE_TEXT, UniBaseNode } from './Node'
export class UniTextNode extends UniBaseNode {
constructor(text: string) {
super(NODE_TYPE_TEXT, '#text')
this._text = text
}
get nodeValue() {
return this._text || ''
}
set nodeValue(text: string) {
this._text = text
}
}
export { UniCommentNode } from './Comment'
export { UniElement, UniInputElement, UniTextAreaElement } from './Element'
export { UniEvent, UniEventListener } from './Event'
export {
NODE_TYPE_PAGE,
NODE_TYPE_ELEMENT,
NODE_TYPE_TEXT,
NODE_TYPE_COMMENT,
UniNode,
UniBaseNode,
UniNodeJSON,
IUniPageNode,
} from './Node'
export { UniTextNode } from './Text'
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册