提交 72bb6b1c 编写于 作者: fxy060608's avatar fxy060608

feat(h5): add lifecycle

上级 84634920
......@@ -6,24 +6,23 @@
@touchend="_hoverTouchEnd"
@touchcancel="_hoverTouchCancel"
@click="_onClick"
v-bind="$attrs"
>
<slot />
</uni-navigator>
<uni-navigator
v-else
@click="_onClick"
v-bind="$attrs"
>
<uni-navigator v-else @click="_onClick">
<slot />
</uni-navigator>
</template>
<script>
import {
hover
} from '../../mixins'
import hover from '../../mixins/hover'
const OPEN_TYPES = ['navigate', 'redirect', 'switchTab', 'reLaunch', 'navigateBack']
const OPEN_TYPES = [
'navigate',
'redirect',
'switchTab',
'reLaunch',
'navigateBack',
]
export default {
name: 'Navigator',
......@@ -31,87 +30,77 @@ export default {
props: {
hoverClass: {
type: String,
default: 'navigator-hover'
default: 'navigator-hover',
},
url: {
type: String,
default: ''
default: '',
},
openType: {
type: String,
default: 'navigate',
validator (value) {
validator(value) {
return ~OPEN_TYPES.indexOf(value)
}
},
},
delta: {
type: Number,
default: 1
default: 1,
},
hoverStartTime: {
type: [Number, String],
default: 20
default: 20,
},
hoverStayTime: {
type: [Number, String],
default: 600
}
default: 600,
},
exists: {
type: String,
default: '',
},
},
methods: {
_onClick ($event) {
_onClick($event) {
if (this.openType !== 'navigateBack' && !this.url) {
console.error('<navigator/> should have url attribute when using navigateTo, redirectTo, reLaunch or switchTab')
console.error(
'<navigator/> should have url attribute when using navigateTo, redirectTo, reLaunch or switchTab'
)
return
}
switch (this.openType) {
case 'navigate':
uni.navigateTo({
url: this.url
url: this.url,
})
break
case 'redirect':
uni.redirectTo({
url: this.url
url: this.url,
exists: this.exists,
})
break
case 'switchTab':
uni.switchTab({
url: this.url
url: this.url,
})
break
case 'reLaunch':
uni.reLaunch({
url: this.url
url: this.url,
})
break
case 'navigateBack':
uni.navigateBack({
delta: this.delta
delta: this.delta,
})
break
default:
break
}
}
}
},
},
}
</script>
<style>
uni-navigator {
height: auto;
width: auto;
display: block;
cursor: pointer;
}
uni-navigator[hidden] {
display: none;
}
.navigator-hover {
background-color: rgba(0, 0, 0, 0.1);
opacity: 0.7;
}
</style>
<template>
<uni-view
v-if="hoverClass && hoverClass !== 'none'"
:class="[hovering?hoverClass:'']"
:class="[hovering ? hoverClass : '']"
@touchstart="_hoverTouchStart"
@touchend="_hoverTouchEnd"
@touchcancel="_hoverTouchCancel"
v-bind="$attrs"
>
<slot />
</uni-view>
<uni-view v-else v-bind="$attrs">
<uni-view v-else>
<slot />
</uni-view>
</template>
......@@ -20,7 +19,7 @@ export default {
name: 'View',
mixins: [hover],
listeners: {
'label-click': 'clickHandler'
}
'label-click': 'clickHandler',
},
}
</script>
......@@ -3393,6 +3393,43 @@ function getTransitionRawChildren(children, keepComment = false) {
}
const isKeepAlive = (vnode) => vnode.type.__isKeepAlive;
class Cache {
constructor(max) {
this.max = max;
this._cache = new Map();
this._keys = new Set();
this._max = parseInt(max, 10);
}
get(key) {
const { _cache, _keys, _max } = this;
const cached = _cache.get(key);
if (cached) {
// make this key the freshest
_keys.delete(key);
_keys.add(key);
}
else {
_keys.add(key);
// prune oldest entry
if (_max && _keys.size > _max) {
const staleKey = _keys.values().next().value;
this.pruneCacheEntry(_cache.get(staleKey));
this.delete(staleKey);
}
}
return cached;
}
set(key, value) {
this._cache.set(key, value);
}
delete(key) {
this._cache.delete(key);
this._keys.delete(key);
}
forEach(fn, thisArg) {
this._cache.forEach(fn.bind(thisArg));
}
}
const KeepAliveImpl = {
name: `KeepAlive`,
// Marker for special handling inside the renderer. We are not using a ===
......@@ -3403,7 +3440,11 @@ const KeepAliveImpl = {
include: [String, RegExp, Array],
exclude: [String, RegExp, Array],
max: [String, Number],
cache: Function // fixed by xxxxxx
matchBy: {
type: String,
default: 'name'
},
cache: Object
},
setup(props, { slots }) {
const instance = getCurrentInstance();
......@@ -3418,14 +3459,35 @@ const KeepAliveImpl = {
if (!sharedContext.renderer) {
return slots.default;
}
const cache = new Map();
const keys = new Set();
if ((process.env.NODE_ENV !== 'production') && props.cache && hasOwn(props, 'max')) {
warn('The `max` prop will be ignored if you provide a custom caching strategy');
}
const cache = props.cache || new Cache(props.max);
cache.pruneCacheEntry = pruneCacheEntry;
let current = null;
function pruneCacheEntry(cached) {
if (!current ||
cached.type !== current.type ||
(props.matchBy === 'key' && cached.key !== current.key)) {
unmount(cached);
}
else if (current) {
// current active instance should no longer be kept-alive.
// we can't unmount it now but it might be later, so reset its flag now.
resetShapeFlag(current);
}
}
const parentSuspense = instance.suspense;
const { renderer: { p: patch, m: move, um: _unmount, o: { createElement } } } = sharedContext;
const storageContainer = createElement('div');
sharedContext.activate = (vnode, container, anchor, isSVG, optimized) => {
const instance = vnode.component;
if (instance.ba) {
const currentState = instance.isDeactivated;
instance.isDeactivated = false;
invokeArrayFns(instance.ba);
instance.isDeactivated = currentState;
}
move(vnode, container, anchor, 0 /* ENTER */, parentSuspense);
// in case props have changed
patch(instance.vnode, vnode, container, anchor, instance, parentSuspense, isSVG, vnode.slotScopeIds, optimized);
......@@ -3442,8 +3504,14 @@ const KeepAliveImpl = {
};
sharedContext.deactivate = (vnode) => {
const instance = vnode.component;
if (instance.bda) {
invokeKeepAliveHooks(instance.bda);
}
move(vnode, storageContainer, null, 1 /* LEAVE */, parentSuspense);
queuePostRenderEffect(() => {
if (instance.bda) {
resetHookState(instance.bda);
}
if (instance.da) {
invokeArrayFns(instance.da);
}
......@@ -3461,29 +3529,15 @@ const KeepAliveImpl = {
}
function pruneCache(filter) {
cache.forEach((vnode, key) => {
const name = getComponentName(vnode.type);
const name = getMatchingName(vnode, props.matchBy);
if (name && (!filter || !filter(name))) {
pruneCacheEntry(key);
cache.delete(key);
pruneCacheEntry(vnode);
}
});
}
function pruneCacheEntry(key) {
const cached = cache.get(key);
if (!current ||
cached.type !== current.type ||
cached.key !== current.key) {
unmount(cached);
}
else if (current) {
// current active instance should no longer be kept-alive.
// we can't unmount it now but it might be later, so reset its flag now.
resetShapeFlag(current);
}
cache.delete(key);
keys.delete(key);
}
// prune cache on include/exclude prop change
watch(() => [props.include, props.exclude], ([include, exclude]) => {
watch(() => [props.include, props.exclude, props.matchBy], ([include, exclude]) => {
include && pruneCache(name => matches(include, name));
exclude && pruneCache(name => !matches(exclude, name));
},
......@@ -3500,10 +3554,17 @@ const KeepAliveImpl = {
onMounted(cacheSubtree);
onUpdated(cacheSubtree);
onBeforeUnmount(() => {
cache.forEach(cached => {
cache.forEach((cached, key) => {
cache.delete(key);
pruneCacheEntry(cached);
const { subTree, suspense } = instance;
const vnode = getInnerChild(subTree);
if (cached.type === vnode.type) {
if (cached.type === vnode.type &&
(props.matchBy !== 'key' || cached.key === vnode.key)) {
// invoke its beforeDeactivate hook here
if (vnode.component.bda) {
invokeArrayFns(vnode.component.bda);
}
// current instance will be unmounted as part of keep-alive's unmount
resetShapeFlag(vnode);
// but invoke its deactivated hook here
......@@ -3511,7 +3572,6 @@ const KeepAliveImpl = {
da && queuePostRenderEffect(da, suspense);
return;
}
unmount(cached);
});
});
return () => {
......@@ -3530,29 +3590,25 @@ const KeepAliveImpl = {
}
else if (!isVNode(rawVNode) ||
(!(rawVNode.shapeFlag & 4 /* STATEFUL_COMPONENT */) &&
!(rawVNode.shapeFlag & 128 /* SUSPENSE */))) {
!isSuspense(rawVNode.type))) {
current = null;
return rawVNode;
}
let vnode = getInnerChild(rawVNode);
const comp = vnode.type;
const name = getComponentName(comp);
const { include, exclude, max } = props;
const name = getMatchingName(vnode, props.matchBy);
const { include, exclude } = props;
if ((include && (!name || !matches(include, name))) ||
(exclude && name && matches(exclude, name))) {
current = vnode;
return rawVNode;
}
const key = vnode.key == null ? comp : vnode.key;
// fixed by xxxxxx
if (typeof props.cache === 'function') {
props.cache(key, cache, pruneCacheEntry);
}
const cachedVNode = cache.get(key);
// clone vnode if it's reused because we are going to mutate it
if (vnode.el) {
vnode = cloneVNode(vnode);
if (rawVNode.shapeFlag & 128 /* SUSPENSE */) {
if (isSuspense(rawVNode.type)) {
rawVNode.ssContent = vnode;
}
}
......@@ -3572,21 +3628,11 @@ const KeepAliveImpl = {
}
// avoid vnode being mounted as fresh
vnode.shapeFlag |= 512 /* COMPONENT_KEPT_ALIVE */;
// make this key the freshest
keys.delete(key);
keys.add(key);
}
else {
keys.add(key);
// prune oldest entry
if (max && keys.size > parseInt(max, 10)) {
pruneCacheEntry(keys.values().next().value);
}
}
// avoid vnode being unmounted
vnode.shapeFlag |= 256 /* COMPONENT_SHOULD_KEEP_ALIVE */;
current = vnode;
return rawVNode;
return isSuspense(rawVNode.type) ? rawVNode : vnode;
};
}
};
......@@ -3606,9 +3652,15 @@ function matches(pattern, name) {
/* istanbul ignore next */
return false;
}
function onBeforeActivate(hook, target) {
registerKeepAliveHook(hook, "ba" /* BEFORE_ACTIVATE */, target);
}
function onActivated(hook, target) {
registerKeepAliveHook(hook, "a" /* ACTIVATED */, target);
}
function onBeforeDeactivate(hook, target) {
registerKeepAliveHook(hook, "bda" /* BEFORE_DEACTIVATE */, target);
}
function onDeactivated(hook, target) {
registerKeepAliveHook(hook, "da" /* DEACTIVATED */, target);
}
......@@ -3628,6 +3680,7 @@ function registerKeepAliveHook(hook, type, target = currentInstance) {
}
hook();
});
wrappedHook.__called = false;
injectHook(type, wrappedHook, target);
// In addition to registering it on the target instance, we walk up the parent
// chain and register it on all ancestor instances that are keep-alive roots.
......@@ -3663,7 +3716,25 @@ function resetShapeFlag(vnode) {
vnode.shapeFlag = shapeFlag;
}
function getInnerChild(vnode) {
return vnode.shapeFlag & 128 /* SUSPENSE */ ? vnode.ssContent : vnode;
return isSuspense(vnode.type) ? vnode.ssContent : vnode;
}
function getMatchingName(vnode, matchBy) {
if (matchBy === 'name') {
return getComponentName(vnode.type);
}
return String(vnode.key);
}
function invokeKeepAliveHooks(hooks) {
for (let i = 0; i < hooks.length; i++) {
const hook = hooks[i];
if (!hook.__called) {
hook();
hook.__called = true;
}
}
}
function resetHookState(hooks) {
hooks.forEach((hook) => (hook.__called = false));
}
const isInternalKey = (key) => key[0] === '_' || key === '$stable';
......@@ -4842,7 +4913,9 @@ function baseCreateRenderer(options, createHydrationFns) {
}
if (parentComponent) {
let subTree = parentComponent.subTree;
if ((process.env.NODE_ENV !== 'production') && subTree.patchFlag & 2048 /* DEV_ROOT_FRAGMENT */) {
if ((process.env.NODE_ENV !== 'production') &&
subTree.patchFlag > 0 &&
subTree.patchFlag & 2048 /* DEV_ROOT_FRAGMENT */) {
subTree =
filterSingleRoot(subTree.children) || subTree;
}
......@@ -5198,12 +5271,14 @@ function baseCreateRenderer(options, createHydrationFns) {
}, parentSuspense);
}
// activated hook for keep-alive roots.
// #1742 activated hook must be accessed after first render
// #1742 beforeActivate/activated hook must be accessed after first render
// since the hook may be injected by a child keep-alive
const { a } = instance;
if (a &&
initialVNode.shapeFlag & 256 /* COMPONENT_SHOULD_KEEP_ALIVE */) {
queuePostRenderEffect(a, parentSuspense);
const { ba, a } = instance;
if (initialVNode.shapeFlag & 256 /* COMPONENT_SHOULD_KEEP_ALIVE */) {
ba && invokeKeepAliveHooks(ba);
a && queuePostRenderEffect(a, parentSuspense);
// reset hook state
ba && queuePostRenderEffect(() => resetHookState(ba), parentSuspense);
}
instance.isMounted = true;
if ((process.env.NODE_ENV !== 'production') || __VUE_PROD_DEVTOOLS__) {
......@@ -5628,7 +5703,10 @@ function baseCreateRenderer(options, createHydrationFns) {
if (shouldInvokeDirs) {
invokeDirectiveHook(vnode, null, parentComponent, 'beforeUnmount');
}
if (dynamicChildren &&
if (shapeFlag & 64 /* TELEPORT */) {
vnode.type.remove(vnode, parentComponent, parentSuspense, optimized, internals, doRemove);
}
else if (dynamicChildren &&
// #1153: fast path should not be taken for non-stable (v-for) fragments
(type !== Fragment ||
(patchFlag > 0 && patchFlag & 64 /* STABLE_FRAGMENT */))) {
......@@ -5641,9 +5719,6 @@ function baseCreateRenderer(options, createHydrationFns) {
(!optimized && shapeFlag & 16 /* ARRAY_CHILDREN */)) {
unmountChildren(children, parentComponent, parentSuspense);
}
if (shapeFlag & 64 /* TELEPORT */) {
vnode.type.remove(vnode, parentComponent, parentSuspense, optimized, internals, doRemove);
}
if (doRemove) {
remove(vnode);
}
......@@ -6647,7 +6722,7 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [],
// assets
components, directives,
// lifecycle
beforeMount, mounted, beforeUpdate, updated, activated, deactivated, beforeDestroy, beforeUnmount, destroyed, unmounted, render, renderTracked, renderTriggered, errorCaptured,
beforeMount, mounted, beforeUpdate, updated, beforeActivate, activated, beforeDeactivate, deactivated, beforeDestroy, beforeUnmount, destroyed, unmounted, render, renderTracked, renderTriggered, errorCaptured,
// public API
expose } = options;
const publicThis = instance.proxy;
......@@ -6857,9 +6932,15 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [],
if (updated) {
onUpdated(updated.bind(publicThis));
}
if (beforeActivate) {
onBeforeActivate(beforeActivate.bind(publicThis));
}
if (activated) {
onActivated(activated.bind(publicThis));
}
if (beforeDeactivate) {
onBeforeDeactivate(beforeDeactivate.bind(publicThis));
}
if (deactivated) {
onDeactivated(deactivated.bind(publicThis));
}
......@@ -7351,7 +7432,9 @@ function createComponentInstance(vnode, parent, suspense) {
u: null,
um: null,
bum: null,
bda: null,
da: null,
ba: null,
a: null,
rtg: null,
rtc: null,
......@@ -9350,4 +9433,4 @@ const onNavigationBarSearchInputClicked = /*#__PURE__*/ createHook("onNavigation
const onNavigationBarSearchInputConfirmed = /*#__PURE__*/ createHook("onNavigationBarSearchInputConfirmed" /* ON_NAVIGATION_BAR_SEARCH_INPUT_CONFIRMED */);
const onNavigationBarSearchInputFocusChanged = /*#__PURE__*/ createHook("onNavigationBarSearchInputFocusChanged" /* ON_NAVIGATION_BAR_SEARCH_INPUT_FOCUS_CHANGED */);
export { BaseTransition, Comment, Fragment, KeepAlive, Static, Suspense, Teleport, Text, Transition, TransitionGroup, callWithAsyncErrorHandling, callWithErrorHandling, cloneVNode, compile$1 as compile, computed$1 as computed, createApp, createBlock, createCommentVNode, createHook, createHydrationRenderer, createRenderer, createSSRApp, createSlots, createStaticVNode, createTextVNode, createVNode, createApp as createVueApp, createSSRApp as createVueSSRApp, customRef, defineAsyncComponent, defineComponent, defineEmit, defineProps, devtools, getCurrentInstance, getTransitionRawChildren, h, handleError, hydrate, initCustomFormatter, inject, injectHook, isInSSRComponentSetup, isProxy, isReactive, isReadonly, isRef, isRuntimeOnly, isVNode, markRaw, mergeProps, nextTick, onActivated, onAddToFavorites, onBackPress, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onError, onErrorCaptured, onHide, onLaunch, onLoad, onMounted, onNavigationBarButtonTap, onNavigationBarSearchInputChanged, onNavigationBarSearchInputClicked, onNavigationBarSearchInputConfirmed, onNavigationBarSearchInputFocusChanged, onPageNotFound, onPageScroll, onPullDownRefresh, onReachBottom, onReady, onRenderTracked, onRenderTriggered, onResize, onShareAppMessage, onShareTimeline, onShow, onTabItemTap, onThemeChange, onUnhandledRejection, onUnload, onUnmounted, onUpdated, openBlock, popScopeId, provide, proxyRefs, pushScopeId, queuePostFlushCb, reactive, readonly, ref, registerRuntimeCompiler, render, renderList, renderSlot, resolveComponent, resolveDirective, resolveDynamicComponent, resolveTransitionHooks, setBlockTracking, setDevtoolsHook, setTransitionHooks, shallowReactive, shallowReadonly, shallowRef, ssrContextKey, ssrUtils, toHandlers, toRaw, toRef, toRefs, transformVNodeArgs, triggerRef, unref, useContext, useCssModule, useCssVars, useSSRContext, useTransitionState, vModelCheckbox, vModelDynamic, vModelRadio, vModelSelect, vModelText, vShow, version, warn, watch, watchEffect, withCtx, withDirectives, withKeys, withModifiers, withScopeId };
export { BaseTransition, Comment, Fragment, KeepAlive, Static, Suspense, Teleport, Text, Transition, TransitionGroup, callWithAsyncErrorHandling, callWithErrorHandling, cloneVNode, compile$1 as compile, computed$1 as computed, createApp, createBlock, createCommentVNode, createHook, createHydrationRenderer, createRenderer, createSSRApp, createSlots, createStaticVNode, createTextVNode, createVNode, createApp as createVueApp, createSSRApp as createVueSSRApp, customRef, defineAsyncComponent, defineComponent, defineEmit, defineProps, devtools, getCurrentInstance, getTransitionRawChildren, h, handleError, hydrate, initCustomFormatter, inject, injectHook, isInSSRComponentSetup, isProxy, isReactive, isReadonly, isRef, isRuntimeOnly, isVNode, markRaw, mergeProps, nextTick, onActivated, onAddToFavorites, onBackPress, onBeforeActivate, onBeforeDeactivate, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onError, onErrorCaptured, onHide, onLaunch, onLoad, onMounted, onNavigationBarButtonTap, onNavigationBarSearchInputChanged, onNavigationBarSearchInputClicked, onNavigationBarSearchInputConfirmed, onNavigationBarSearchInputFocusChanged, onPageNotFound, onPageScroll, onPullDownRefresh, onReachBottom, onReady, onRenderTracked, onRenderTriggered, onResize, onShareAppMessage, onShareTimeline, onShow, onTabItemTap, onThemeChange, onUnhandledRejection, onUnload, onUnmounted, onUpdated, openBlock, popScopeId, provide, proxyRefs, pushScopeId, queuePostFlushCb, reactive, readonly, ref, registerRuntimeCompiler, render, renderList, renderSlot, resolveComponent, resolveDirective, resolveDynamicComponent, resolveTransitionHooks, setBlockTracking, setDevtoolsHook, setTransitionHooks, shallowReactive, shallowReadonly, shallowRef, ssrContextKey, ssrUtils, toHandlers, toRaw, toRef, toRefs, transformVNodeArgs, triggerRef, unref, useContext, useCssModule, useCssVars, useSSRContext, useTransitionState, vModelCheckbox, vModelDynamic, vModelRadio, vModelSelect, vModelText, vShow, version, warn, watch, watchEffect, withCtx, withDirectives, withKeys, withModifiers, withScopeId };
......@@ -3393,6 +3393,43 @@ function getTransitionRawChildren(children, keepComment = false) {
}
const isKeepAlive = (vnode) => vnode.type.__isKeepAlive;
class Cache {
constructor(max) {
this.max = max;
this._cache = new Map();
this._keys = new Set();
this._max = parseInt(max, 10);
}
get(key) {
const { _cache, _keys, _max } = this;
const cached = _cache.get(key);
if (cached) {
// make this key the freshest
_keys.delete(key);
_keys.add(key);
}
else {
_keys.add(key);
// prune oldest entry
if (_max && _keys.size > _max) {
const staleKey = _keys.values().next().value;
this.pruneCacheEntry(_cache.get(staleKey));
this.delete(staleKey);
}
}
return cached;
}
set(key, value) {
this._cache.set(key, value);
}
delete(key) {
this._cache.delete(key);
this._keys.delete(key);
}
forEach(fn, thisArg) {
this._cache.forEach(fn.bind(thisArg));
}
}
const KeepAliveImpl = {
name: `KeepAlive`,
// Marker for special handling inside the renderer. We are not using a ===
......@@ -3403,7 +3440,11 @@ const KeepAliveImpl = {
include: [String, RegExp, Array],
exclude: [String, RegExp, Array],
max: [String, Number],
cache: Function // fixed by xxxxxx
matchBy: {
type: String,
default: 'name'
},
cache: Object
},
setup(props, { slots }) {
const instance = getCurrentInstance();
......@@ -3418,14 +3459,35 @@ const KeepAliveImpl = {
if (!sharedContext.renderer) {
return slots.default;
}
const cache = new Map();
const keys = new Set();
if ((process.env.NODE_ENV !== 'production') && props.cache && hasOwn(props, 'max')) {
warn('The `max` prop will be ignored if you provide a custom caching strategy');
}
const cache = props.cache || new Cache(props.max);
cache.pruneCacheEntry = pruneCacheEntry;
let current = null;
function pruneCacheEntry(cached) {
if (!current ||
cached.type !== current.type ||
(props.matchBy === 'key' && cached.key !== current.key)) {
unmount(cached);
}
else if (current) {
// current active instance should no longer be kept-alive.
// we can't unmount it now but it might be later, so reset its flag now.
resetShapeFlag(current);
}
}
const parentSuspense = instance.suspense;
const { renderer: { p: patch, m: move, um: _unmount, o: { createElement } } } = sharedContext;
const storageContainer = createElement('div');
sharedContext.activate = (vnode, container, anchor, isSVG, optimized) => {
const instance = vnode.component;
if (instance.ba) {
const currentState = instance.isDeactivated;
instance.isDeactivated = false;
invokeArrayFns(instance.ba);
instance.isDeactivated = currentState;
}
move(vnode, container, anchor, 0 /* ENTER */, parentSuspense);
// in case props have changed
patch(instance.vnode, vnode, container, anchor, instance, parentSuspense, isSVG, vnode.slotScopeIds, optimized);
......@@ -3442,8 +3504,14 @@ const KeepAliveImpl = {
};
sharedContext.deactivate = (vnode) => {
const instance = vnode.component;
if (instance.bda) {
invokeKeepAliveHooks(instance.bda);
}
move(vnode, storageContainer, null, 1 /* LEAVE */, parentSuspense);
queuePostRenderEffect(() => {
if (instance.bda) {
resetHookState(instance.bda);
}
if (instance.da) {
invokeArrayFns(instance.da);
}
......@@ -3461,29 +3529,15 @@ const KeepAliveImpl = {
}
function pruneCache(filter) {
cache.forEach((vnode, key) => {
const name = getComponentName(vnode.type);
const name = getMatchingName(vnode, props.matchBy);
if (name && (!filter || !filter(name))) {
pruneCacheEntry(key);
cache.delete(key);
pruneCacheEntry(vnode);
}
});
}
function pruneCacheEntry(key) {
const cached = cache.get(key);
if (!current ||
cached.type !== current.type ||
cached.key !== current.key) {
unmount(cached);
}
else if (current) {
// current active instance should no longer be kept-alive.
// we can't unmount it now but it might be later, so reset its flag now.
resetShapeFlag(current);
}
cache.delete(key);
keys.delete(key);
}
// prune cache on include/exclude prop change
watch(() => [props.include, props.exclude], ([include, exclude]) => {
watch(() => [props.include, props.exclude, props.matchBy], ([include, exclude]) => {
include && pruneCache(name => matches(include, name));
exclude && pruneCache(name => !matches(exclude, name));
},
......@@ -3500,10 +3554,17 @@ const KeepAliveImpl = {
onMounted(cacheSubtree);
onUpdated(cacheSubtree);
onBeforeUnmount(() => {
cache.forEach(cached => {
cache.forEach((cached, key) => {
cache.delete(key);
pruneCacheEntry(cached);
const { subTree, suspense } = instance;
const vnode = getInnerChild(subTree);
if (cached.type === vnode.type) {
if (cached.type === vnode.type &&
(props.matchBy !== 'key' || cached.key === vnode.key)) {
// invoke its beforeDeactivate hook here
if (vnode.component.bda) {
invokeArrayFns(vnode.component.bda);
}
// current instance will be unmounted as part of keep-alive's unmount
resetShapeFlag(vnode);
// but invoke its deactivated hook here
......@@ -3511,7 +3572,6 @@ const KeepAliveImpl = {
da && queuePostRenderEffect(da, suspense);
return;
}
unmount(cached);
});
});
return () => {
......@@ -3530,29 +3590,25 @@ const KeepAliveImpl = {
}
else if (!isVNode(rawVNode) ||
(!(rawVNode.shapeFlag & 4 /* STATEFUL_COMPONENT */) &&
!(rawVNode.shapeFlag & 128 /* SUSPENSE */))) {
!isSuspense(rawVNode.type))) {
current = null;
return rawVNode;
}
let vnode = getInnerChild(rawVNode);
const comp = vnode.type;
const name = getComponentName(comp);
const { include, exclude, max } = props;
const name = getMatchingName(vnode, props.matchBy);
const { include, exclude } = props;
if ((include && (!name || !matches(include, name))) ||
(exclude && name && matches(exclude, name))) {
current = vnode;
return rawVNode;
}
const key = vnode.key == null ? comp : vnode.key;
// fixed by xxxxxx
if (typeof props.cache === 'function') {
props.cache(key, cache, pruneCacheEntry);
}
const cachedVNode = cache.get(key);
// clone vnode if it's reused because we are going to mutate it
if (vnode.el) {
vnode = cloneVNode(vnode);
if (rawVNode.shapeFlag & 128 /* SUSPENSE */) {
if (isSuspense(rawVNode.type)) {
rawVNode.ssContent = vnode;
}
}
......@@ -3572,21 +3628,11 @@ const KeepAliveImpl = {
}
// avoid vnode being mounted as fresh
vnode.shapeFlag |= 512 /* COMPONENT_KEPT_ALIVE */;
// make this key the freshest
keys.delete(key);
keys.add(key);
}
else {
keys.add(key);
// prune oldest entry
if (max && keys.size > parseInt(max, 10)) {
pruneCacheEntry(keys.values().next().value);
}
}
// avoid vnode being unmounted
vnode.shapeFlag |= 256 /* COMPONENT_SHOULD_KEEP_ALIVE */;
current = vnode;
return rawVNode;
return isSuspense(rawVNode.type) ? rawVNode : vnode;
};
}
};
......@@ -3606,9 +3652,15 @@ function matches(pattern, name) {
/* istanbul ignore next */
return false;
}
function onBeforeActivate(hook, target) {
registerKeepAliveHook(hook, "ba" /* BEFORE_ACTIVATE */, target);
}
function onActivated(hook, target) {
registerKeepAliveHook(hook, "a" /* ACTIVATED */, target);
}
function onBeforeDeactivate(hook, target) {
registerKeepAliveHook(hook, "bda" /* BEFORE_DEACTIVATE */, target);
}
function onDeactivated(hook, target) {
registerKeepAliveHook(hook, "da" /* DEACTIVATED */, target);
}
......@@ -3628,6 +3680,7 @@ function registerKeepAliveHook(hook, type, target = currentInstance) {
}
hook();
});
wrappedHook.__called = false;
injectHook(type, wrappedHook, target);
// In addition to registering it on the target instance, we walk up the parent
// chain and register it on all ancestor instances that are keep-alive roots.
......@@ -3663,7 +3716,25 @@ function resetShapeFlag(vnode) {
vnode.shapeFlag = shapeFlag;
}
function getInnerChild(vnode) {
return vnode.shapeFlag & 128 /* SUSPENSE */ ? vnode.ssContent : vnode;
return isSuspense(vnode.type) ? vnode.ssContent : vnode;
}
function getMatchingName(vnode, matchBy) {
if (matchBy === 'name') {
return getComponentName(vnode.type);
}
return String(vnode.key);
}
function invokeKeepAliveHooks(hooks) {
for (let i = 0; i < hooks.length; i++) {
const hook = hooks[i];
if (!hook.__called) {
hook();
hook.__called = true;
}
}
}
function resetHookState(hooks) {
hooks.forEach((hook) => (hook.__called = false));
}
const isInternalKey = (key) => key[0] === '_' || key === '$stable';
......@@ -4842,7 +4913,9 @@ function baseCreateRenderer(options, createHydrationFns) {
}
if (parentComponent) {
let subTree = parentComponent.subTree;
if ((process.env.NODE_ENV !== 'production') && subTree.patchFlag & 2048 /* DEV_ROOT_FRAGMENT */) {
if ((process.env.NODE_ENV !== 'production') &&
subTree.patchFlag > 0 &&
subTree.patchFlag & 2048 /* DEV_ROOT_FRAGMENT */) {
subTree =
filterSingleRoot(subTree.children) || subTree;
}
......@@ -5198,12 +5271,14 @@ function baseCreateRenderer(options, createHydrationFns) {
}, parentSuspense);
}
// activated hook for keep-alive roots.
// #1742 activated hook must be accessed after first render
// #1742 beforeActivate/activated hook must be accessed after first render
// since the hook may be injected by a child keep-alive
const { a } = instance;
if (a &&
initialVNode.shapeFlag & 256 /* COMPONENT_SHOULD_KEEP_ALIVE */) {
queuePostRenderEffect(a, parentSuspense);
const { ba, a } = instance;
if (initialVNode.shapeFlag & 256 /* COMPONENT_SHOULD_KEEP_ALIVE */) {
ba && invokeKeepAliveHooks(ba);
a && queuePostRenderEffect(a, parentSuspense);
// reset hook state
ba && queuePostRenderEffect(() => resetHookState(ba), parentSuspense);
}
instance.isMounted = true;
if ((process.env.NODE_ENV !== 'production') || __VUE_PROD_DEVTOOLS__) {
......@@ -5628,7 +5703,10 @@ function baseCreateRenderer(options, createHydrationFns) {
if (shouldInvokeDirs) {
invokeDirectiveHook(vnode, null, parentComponent, 'beforeUnmount');
}
if (dynamicChildren &&
if (shapeFlag & 64 /* TELEPORT */) {
vnode.type.remove(vnode, parentComponent, parentSuspense, optimized, internals, doRemove);
}
else if (dynamicChildren &&
// #1153: fast path should not be taken for non-stable (v-for) fragments
(type !== Fragment ||
(patchFlag > 0 && patchFlag & 64 /* STABLE_FRAGMENT */))) {
......@@ -5641,9 +5719,6 @@ function baseCreateRenderer(options, createHydrationFns) {
(!optimized && shapeFlag & 16 /* ARRAY_CHILDREN */)) {
unmountChildren(children, parentComponent, parentSuspense);
}
if (shapeFlag & 64 /* TELEPORT */) {
vnode.type.remove(vnode, parentComponent, parentSuspense, optimized, internals, doRemove);
}
if (doRemove) {
remove(vnode);
}
......@@ -6647,7 +6722,7 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [],
// assets
components, directives,
// lifecycle
beforeMount, mounted, beforeUpdate, updated, activated, deactivated, beforeDestroy, beforeUnmount, destroyed, unmounted, render, renderTracked, renderTriggered, errorCaptured,
beforeMount, mounted, beforeUpdate, updated, beforeActivate, activated, beforeDeactivate, deactivated, beforeDestroy, beforeUnmount, destroyed, unmounted, render, renderTracked, renderTriggered, errorCaptured,
// public API
expose } = options;
const publicThis = instance.proxy;
......@@ -6857,9 +6932,15 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [],
if (updated) {
onUpdated(updated.bind(publicThis));
}
if (beforeActivate) {
onBeforeActivate(beforeActivate.bind(publicThis));
}
if (activated) {
onActivated(activated.bind(publicThis));
}
if (beforeDeactivate) {
onBeforeDeactivate(beforeDeactivate.bind(publicThis));
}
if (deactivated) {
onDeactivated(deactivated.bind(publicThis));
}
......@@ -7351,7 +7432,9 @@ function createComponentInstance(vnode, parent, suspense) {
u: null,
um: null,
bum: null,
bda: null,
da: null,
ba: null,
a: null,
rtg: null,
rtc: null,
......@@ -9321,4 +9404,4 @@ const compile$1 = () => {
}
};
export { BaseTransition, Comment, Fragment, KeepAlive, Static, Suspense, Teleport, Text, Transition, TransitionGroup, callWithAsyncErrorHandling, callWithErrorHandling, cloneVNode, compile$1 as compile, computed$1 as computed, createApp, createBlock, createCommentVNode, createHydrationRenderer, createRenderer, createSSRApp, createSlots, createStaticVNode, createTextVNode, createVNode, createApp as createVueApp, createSSRApp as createVueSSRApp, customRef, defineAsyncComponent, defineComponent, defineEmit, defineProps, devtools, getCurrentInstance, getTransitionRawChildren, h, handleError, hydrate, initCustomFormatter, inject, injectHook, isInSSRComponentSetup, isProxy, isReactive, isReadonly, isRef, isRuntimeOnly, isVNode, markRaw, mergeProps, nextTick, onActivated, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onErrorCaptured, onMounted, onRenderTracked, onRenderTriggered, onUnmounted, onUpdated, openBlock, popScopeId, provide, proxyRefs, pushScopeId, queuePostFlushCb, reactive, readonly, ref, registerRuntimeCompiler, render, renderList, renderSlot, resolveComponent, resolveDirective, resolveDynamicComponent, resolveTransitionHooks, setBlockTracking, setDevtoolsHook, setTransitionHooks, shallowReactive, shallowReadonly, shallowRef, ssrContextKey, ssrUtils, toHandlers, toRaw, toRef, toRefs, transformVNodeArgs, triggerRef, unref, useContext, useCssModule, useCssVars, useSSRContext, useTransitionState, vModelCheckbox, vModelDynamic, vModelRadio, vModelSelect, vModelText, vShow, version, warn, watch, watchEffect, withCtx, withDirectives, withKeys, withModifiers, withScopeId };
export { BaseTransition, Comment, Fragment, KeepAlive, Static, Suspense, Teleport, Text, Transition, TransitionGroup, callWithAsyncErrorHandling, callWithErrorHandling, cloneVNode, compile$1 as compile, computed$1 as computed, createApp, createBlock, createCommentVNode, createHydrationRenderer, createRenderer, createSSRApp, createSlots, createStaticVNode, createTextVNode, createVNode, createApp as createVueApp, createSSRApp as createVueSSRApp, customRef, defineAsyncComponent, defineComponent, defineEmit, defineProps, devtools, getCurrentInstance, getTransitionRawChildren, h, handleError, hydrate, initCustomFormatter, inject, injectHook, isInSSRComponentSetup, isProxy, isReactive, isReadonly, isRef, isRuntimeOnly, isVNode, markRaw, mergeProps, nextTick, onActivated, onBeforeActivate, onBeforeDeactivate, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onErrorCaptured, onMounted, onRenderTracked, onRenderTriggered, onUnmounted, onUpdated, openBlock, popScopeId, provide, proxyRefs, pushScopeId, queuePostFlushCb, reactive, readonly, ref, registerRuntimeCompiler, render, renderList, renderSlot, resolveComponent, resolveDirective, resolveDynamicComponent, resolveTransitionHooks, setBlockTracking, setDevtoolsHook, setTransitionHooks, shallowReactive, shallowReadonly, shallowRef, ssrContextKey, ssrUtils, toHandlers, toRaw, toRef, toRefs, transformVNodeArgs, triggerRef, unref, useContext, useCssModule, useCssVars, useSSRContext, useTransitionState, vModelCheckbox, vModelDynamic, vModelRadio, vModelSelect, vModelText, vShow, version, warn, watch, watchEffect, withCtx, withDirectives, withKeys, withModifiers, withScopeId };
uni-canvas {
width: 300px;
height: 150px;
display: block;
position: relative;
}
uni-canvas > canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
uni-checkbox-group[hidden] {
display: none;
}
.ql-container {
display: block;
position: relative;
box-sizing: border-box;
-webkit-user-select: text;
user-select: text;
outline: none;
overflow: hidden;
width: 100%;
height: 200px;
min-height: 200px;
}
.ql-container[hidden] {
display: none;
}
.ql-container .ql-editor {
position: relative;
font-size: inherit;
line-height: inherit;
font-family: inherit;
min-height: inherit;
width: 100%;
height: 100%;
padding: 0;
overflow-x: hidden;
overflow-y: auto;
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
-webkit-overflow-scrolling: touch;
}
.ql-container .ql-editor::-webkit-scrollbar {
width: 0 !important;
}
.ql-container .ql-editor.scroll-disabled {
overflow: hidden;
}
.ql-container .ql-image-overlay {
display: flex;
position: absolute;
box-sizing: border-box;
border: 1px dashed #ccc;
justify-content: center;
align-items: center;
-webkit-user-select: none;
user-select: none;
}
.ql-container .ql-image-overlay .ql-image-size {
position: absolute;
padding: 4px 8px;
text-align: center;
background-color: #fff;
color: #888;
border: 1px solid #ccc;
box-sizing: border-box;
opacity: 0.8;
right: 4px;
top: 4px;
font-size: 12px;
display: inline-block;
width: auto;
}
.ql-container .ql-image-overlay .ql-image-toolbar {
position: relative;
text-align: center;
box-sizing: border-box;
background: #000;
border-radius: 5px;
color: #fff;
font-size: 0;
min-height: 24px;
z-index: 100;
}
.ql-container .ql-image-overlay .ql-image-toolbar span {
display: inline-block;
cursor: pointer;
padding: 5px;
font-size: 12px;
border-right: 1px solid #fff;
}
.ql-container .ql-image-overlay .ql-image-toolbar span:last-child {
border-right: 0;
}
.ql-container .ql-image-overlay .ql-image-toolbar span.triangle-up {
padding: 0;
position: absolute;
top: -12px;
left: 50%;
transform: translatex(-50%);
width: 0;
height: 0;
border-width: 6px;
border-style: solid;
border-color: transparent transparent black transparent;
}
.ql-container .ql-image-overlay .ql-image-handle {
position: absolute;
height: 12px;
width: 12px;
border-radius: 50%;
border: 1px solid #ccc;
box-sizing: border-box;
background: #fff;
}
.ql-container img {
display: inline-block;
max-width: 100%;
}
.ql-clipboard p {
margin: 0;
padding: 0;
}
.ql-editor {
box-sizing: border-box;
height: 100%;
outline: none;
overflow-y: auto;
tab-size: 4;
-moz-tab-size: 4;
text-align: left;
white-space: pre-wrap;
word-wrap: break-word;
}
.ql-editor > * {
cursor: text;
}
.ql-editor p,
.ql-editor ol,
.ql-editor ul,
.ql-editor pre,
.ql-editor blockquote,
.ql-editor h1,
.ql-editor h2,
.ql-editor h3,
.ql-editor h4,
.ql-editor h5,
.ql-editor h6 {
margin: 0;
padding: 0;
counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol > li,
.ql-editor ul > li {
list-style-type: none;
}
.ql-editor ul > li::before {
content: '\2022';
}
.ql-editor ul[data-checked=true],
.ql-editor ul[data-checked=false] {
pointer-events: none;
}
.ql-editor ul[data-checked=true] > li *,
.ql-editor ul[data-checked=false] > li * {
pointer-events: all;
}
.ql-editor ul[data-checked=true] > li::before,
.ql-editor ul[data-checked=false] > li::before {
color: #777;
cursor: pointer;
pointer-events: all;
}
.ql-editor ul[data-checked=true] > li::before {
content: '\2611';
}
.ql-editor ul[data-checked=false] > li::before {
content: '\2610';
}
.ql-editor li::before {
display: inline-block;
white-space: nowrap;
width: 2em;
}
.ql-editor ol li {
counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
counter-increment: list-0;
}
.ql-editor ol li:before {
content: counter(list-0, decimal) '. ';
}
.ql-editor ol li.ql-indent-1 {
counter-increment: list-1;
}
.ql-editor ol li.ql-indent-1:before {
content: counter(list-1, lower-alpha) '. ';
}
.ql-editor ol li.ql-indent-1 {
counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-2 {
counter-increment: list-2;
}
.ql-editor ol li.ql-indent-2:before {
content: counter(list-2, lower-roman) '. ';
}
.ql-editor ol li.ql-indent-2 {
counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-3 {
counter-increment: list-3;
}
.ql-editor ol li.ql-indent-3:before {
content: counter(list-3, decimal) '. ';
}
.ql-editor ol li.ql-indent-3 {
counter-reset: list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-4 {
counter-increment: list-4;
}
.ql-editor ol li.ql-indent-4:before {
content: counter(list-4, lower-alpha) '. ';
}
.ql-editor ol li.ql-indent-4 {
counter-reset: list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-5 {
counter-increment: list-5;
}
.ql-editor ol li.ql-indent-5:before {
content: counter(list-5, lower-roman) '. ';
}
.ql-editor ol li.ql-indent-5 {
counter-reset: list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-6 {
counter-increment: list-6;
}
.ql-editor ol li.ql-indent-6:before {
content: counter(list-6, decimal) '. ';
}
.ql-editor ol li.ql-indent-6 {
counter-reset: list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-7 {
counter-increment: list-7;
}
.ql-editor ol li.ql-indent-7:before {
content: counter(list-7, lower-alpha) '. ';
}
.ql-editor ol li.ql-indent-7 {
counter-reset: list-8 list-9;
}
.ql-editor ol li.ql-indent-8 {
counter-increment: list-8;
}
.ql-editor ol li.ql-indent-8:before {
content: counter(list-8, lower-roman) '. ';
}
.ql-editor ol li.ql-indent-8 {
counter-reset: list-9;
}
.ql-editor ol li.ql-indent-9 {
counter-increment: list-9;
}
.ql-editor ol li.ql-indent-9:before {
content: counter(list-9, decimal) '. ';
}
.ql-editor .ql-indent-1:not(.ql-direction-rtl) {
padding-left: 2em;
}
.ql-editor li.ql-indent-1:not(.ql-direction-rtl) {
padding-left: 2em;
}
.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right {
padding-right: 2em;
}
.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right {
padding-right: 2em;
}
.ql-editor .ql-indent-2:not(.ql-direction-rtl) {
padding-left: 4em;
}
.ql-editor li.ql-indent-2:not(.ql-direction-rtl) {
padding-left: 4em;
}
.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right {
padding-right: 4em;
}
.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right {
padding-right: 4em;
}
.ql-editor .ql-indent-3:not(.ql-direction-rtl) {
padding-left: 6em;
}
.ql-editor li.ql-indent-3:not(.ql-direction-rtl) {
padding-left: 6em;
}
.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right {
padding-right: 6em;
}
.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right {
padding-right: 6em;
}
.ql-editor .ql-indent-4:not(.ql-direction-rtl) {
padding-left: 8em;
}
.ql-editor li.ql-indent-4:not(.ql-direction-rtl) {
padding-left: 8em;
}
.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right {
padding-right: 8em;
}
.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right {
padding-right: 8em;
}
.ql-editor .ql-indent-5:not(.ql-direction-rtl) {
padding-left: 10em;
}
.ql-editor li.ql-indent-5:not(.ql-direction-rtl) {
padding-left: 10em;
}
.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right {
padding-right: 10em;
}
.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right {
padding-right: 10em;
}
.ql-editor .ql-indent-6:not(.ql-direction-rtl) {
padding-left: 12em;
}
.ql-editor li.ql-indent-6:not(.ql-direction-rtl) {
padding-left: 12em;
}
.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right {
padding-right: 12em;
}
.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right {
padding-right: 12em;
}
.ql-editor .ql-indent-7:not(.ql-direction-rtl) {
padding-left: 14em;
}
.ql-editor li.ql-indent-7:not(.ql-direction-rtl) {
padding-left: 14em;
}
.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right {
padding-right: 14em;
}
.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right {
padding-right: 14em;
}
.ql-editor .ql-indent-8:not(.ql-direction-rtl) {
padding-left: 16em;
}
.ql-editor li.ql-indent-8:not(.ql-direction-rtl) {
padding-left: 16em;
}
.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right {
padding-right: 16em;
}
.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right {
padding-right: 16em;
}
.ql-editor .ql-indent-9:not(.ql-direction-rtl) {
padding-left: 18em;
}
.ql-editor li.ql-indent-9:not(.ql-direction-rtl) {
padding-left: 18em;
}
.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right {
padding-right: 18em;
}
.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right {
padding-right: 18em;
}
.ql-editor .ql-direction-rtl {
direction: rtl;
text-align: inherit;
}
.ql-editor .ql-align-center {
text-align: center;
}
.ql-editor .ql-align-justify {
text-align: justify;
}
.ql-editor .ql-align-right {
text-align: right;
}
.ql-editor.ql-blank::before {
color: rgba(0, 0, 0, 0.6);
content: attr(data-placeholder);
font-style: italic;
pointer-events: none;
position: absolute;
}
.ql-container.ql-disabled .ql-editor ul[data-checked] > li::before {
pointer-events: none;
}
.ql-clipboard {
left: -100000px;
height: 1px;
overflow-y: hidden;
position: absolute;
top: 50%;
}
uni-image {
width: 320px;
height: 240px;
display: inline-block;
overflow: hidden;
position: relative;
}
uni-image[hidden] {
display: none;
}
uni-image > div {
width: 100%;
height: 100%;
}
uni-image > img {
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
}
uni-image > .uni-image-will-change {
will-change: transform;
}
.uni-label-pointer {
cursor: pointer;
}
uni-movable-view {
display: inline-block;
width: 10px;
height: 10px;
top: 0px;
left: 0px;
position: absolute;
cursor: grab;
}
uni-movable-view[hidden] {
display: none;
}
uni-radio {
-webkit-tap-highlight-color: transparent;
display: inline-block;
cursor: pointer;
}
uni-radio[hidden] {
display: none;
}
uni-radio[disabled] {
cursor: not-allowed;
}
uni-radio .uni-radio-wrapper {
display: -webkit-inline-flex;
display: inline-flex;
-webkit-align-items: center;
align-items: center;
vertical-align: middle;
}
uni-radio .uni-radio-input {
-webkit-appearance: none;
appearance: none;
margin-right: 5px;
outline: 0;
border: 1px solid #D1D1D1;
background-color: #ffffff;
border-radius: 50%;
width: 22px;
height: 22px;
position: relative;
}
uni-radio:not([disabled]) .uni-radio-input:hover {
border-color: #007aff;
}
uni-radio .uni-radio-input.uni-radio-input-checked:before {
font: normal normal normal 14px/1 "uni";
content: "\EA08";
color: #ffffff;
font-size: 18px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -48%) scale(0.73);
-webkit-transform: translate(-50%, -48%) scale(0.73);
}
uni-radio .uni-radio-input.uni-radio-input-disabled {
background-color: #E1E1E1;
border-color: #D1D1D1;
}
uni-radio .uni-radio-input.uni-radio-input-disabled:before {
color: #ADADAD;
}
uni-radio-group {
display: block;
}
uni-radio-group[hidden] {
display: none;
}
@keyframes once-show {
from {
top: 0;
}
}
uni-resize-sensor,
uni-resize-sensor > div {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
overflow: hidden;
}
uni-resize-sensor {
display: block;
z-index: -1;
visibility: hidden;
animation: once-show 1ms;
}
uni-resize-sensor > div > div {
position: absolute;
left: 0;
top: 0;
}
uni-resize-sensor > div:first-child > div {
width: 100000px;
height: 100000px;
}
uni-resize-sensor > div:last-child > div {
width: 200%;
height: 200%;
}
uni-scroll-view {
display: block;
width: 100%;
}
uni-scroll-view[hidden] {
display: none;
}
.uni-scroll-view {
position: relative;
-webkit-overflow-scrolling: touch;
width: 100%;
/* display: flex; 时在安卓下会导致scrollWidth和offsetWidth一样 */
height: 100%;
max-height: inherit;
}
.uni-scroll-view-content {
width: 100%;
height: 100%;
}
.uni-scroll-view-refresher {
position: relative;
overflow: hidden;
}
.uni-scroll-view-refresh {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.uni-scroll-view-refresh-inner {
display: flex;
align-items: center;
justify-content: center;
line-height: 0;
width: 40px;
height: 40px;
border-radius: 50%;
background-color: #fff;
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.117647),
0 1px 4px rgba(0, 0, 0, 0.117647);
}
.uni-scroll-view-refresh__spinner {
transform-origin: center center;
animation: uni-scroll-view-refresh-rotate 2s linear infinite;
}
.uni-scroll-view-refresh__spinner > circle {
stroke: currentColor;
stroke-linecap: round;
animation: uni-scroll-view-refresh-dash 2s linear infinite;
}
@keyframes uni-scroll-view-refresh-rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes uni-scroll-view-refresh-dash {
0% {
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 89, 200;
stroke-dashoffset: -35px;
}
100% {
stroke-dasharray: 89, 200;
stroke-dashoffset: -124px;
}
}
uni-swiper-item {
display: block;
overflow: hidden;
will-change: transform;
position: absolute;
width: 100%;
height: 100%;
cursor: grab;
}
uni-swiper-item[hidden] {
display: none;
}
uni-switch {
-webkit-tap-highlight-color: transparent;
display: inline-block;
cursor: pointer;
}
uni-switch[hidden] {
display: none;
}
uni-switch[disabled] {
cursor: not-allowed;
}
uni-switch .uni-switch-wrapper {
display: -webkit-inline-flex;
display: inline-flex;
-webkit-align-items: center;
align-items: center;
vertical-align: middle;
}
uni-switch .uni-switch-input {
-webkit-appearance: none;
appearance: none;
position: relative;
width: 52px;
height: 32px;
margin-right: 5px;
border: 1px solid #DFDFDF;
outline: 0;
border-radius: 16px;
box-sizing: border-box;
background-color: #DFDFDF;
transition: background-color 0.1s, border 0.1s;
}
uni-switch[disabled] .uni-switch-input {
opacity: .7;
}
uni-switch .uni-switch-input:before {
content: " ";
position: absolute;
top: 0;
left: 0;
width: 50px;
height: 30px;
border-radius: 15px;
background-color: #FDFDFD;
transition: -webkit-transform 0.3s;
transition: transform 0.3s;
transition: transform 0.3s, -webkit-transform 0.3s;
}
uni-switch .uni-switch-input:after {
content: " ";
position: absolute;
top: 0;
left: 0;
width: 30px;
height: 30px;
border-radius: 15px;
background-color: #FFFFFF;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
transition: -webkit-transform 0.3s;
transition: transform 0.3s;
transition: transform 0.3s, -webkit-transform 0.3s;
}
uni-switch .uni-switch-input.uni-switch-input-checked {
border-color: #007aff;
background-color: #007aff;
}
uni-switch .uni-switch-input.uni-switch-input-checked:before {
-webkit-transform: scale(0);
transform: scale(0);
}
uni-switch .uni-switch-input.uni-switch-input-checked:after {
-webkit-transform: translateX(20px);
transform: translateX(20px);
}
uni-switch .uni-checkbox-input {
margin-right: 5px;
-webkit-appearance: none;
appearance: none;
outline: 0;
border: 1px solid #D1D1D1;
background-color: #FFFFFF;
border-radius: 3px;
width: 22px;
height: 22px;
position: relative;
color: #007aff;
}
uni-switch:not([disabled]) .uni-checkbox-input:hover {
border-color: #007aff;
}
uni-switch .uni-checkbox-input.uni-checkbox-input-checked:before {
font: normal normal normal 14px/1 "uni";
content: "\EA08";
color: inherit;
font-size: 22px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -48%) scale(0.73);
-webkit-transform: translate(-50%, -48%) scale(0.73);
}
uni-switch .uni-checkbox-input.uni-checkbox-input-disabled {
background-color: #E1E1E1;
}
uni-switch .uni-checkbox-input.uni-checkbox-input-disabled:before {
color: #ADADAD;
}
uni-text[selectable] {
cursor: auto;
user-select: text;
-webkit-user-select: text;
}
uni-textarea {
width: 300px;
height: 150px;
display: block;
position: relative;
font-size: 16px;
line-height: normal;
white-space: pre-wrap;
word-break: break-all;
}
uni-textarea[hidden] {
display: none;
}
.uni-textarea-wrapper,
.uni-textarea-placeholder,
.uni-textarea-line,
.uni-textarea-compute,
.uni-textarea-textarea {
outline: none;
border: none;
padding: 0;
margin: 0;
text-decoration: inherit;
}
.uni-textarea-wrapper {
display: block;
position: relative;
width: 100%;
height: 100%;
}
.uni-textarea-placeholder,
.uni-textarea-line,
.uni-textarea-compute,
.uni-textarea-textarea {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
white-space: inherit;
word-break: inherit;
}
.uni-textarea-placeholder {
color: grey;
overflow: hidden;
}
.uni-textarea-line,
.uni-textarea-compute {
visibility: hidden;
height: auto;
}
.uni-textarea-line {
width: 1em;
}
.uni-textarea-textarea {
resize: none;
background: none;
color: inherit;
opacity: 1;
-webkit-text-fill-color: currentcolor;
font: inherit;
line-height: inherit;
letter-spacing: inherit;
text-align: inherit;
text-indent: inherit;
text-transform: inherit;
text-shadow: inherit;
}
/* 用于解决 iOS textarea 内部默认边距 */
.uni-textarea-textarea-fix-margin {
width: auto;
right: 0;
margin: 0 -3px;
}
.uni-async-error {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
color: #999;
padding: 100px 10px;
text-align: center;
}
.uni-async-loading {
box-sizing: border-box;
width: 100%;
padding: 50px;
text-align: center;
}
.uni-async-loading .uni-loading {
width: 30px;
height: 30px;
}
此差异已折叠。
......@@ -94,11 +94,11 @@ function createRouterViewVNode(
keepAliveRoute: ReturnType<typeof useKeepAliveRoute>
) {
return createVNode(RouterView, null, {
default: withCtx(({ Component }) => [
default: withCtx(({ Component }: { Component: unknown }) => [
(openBlock(),
createBlock(
KeepAlive,
{ cache: keepAliveRoute.routeCache },
{ matchBy: 'key', cache: keepAliveRoute.routeCache },
[
(openBlock(),
createBlock(resolveDynamicComponent(Component), {
......
......@@ -57,8 +57,17 @@ export default /*#__PURE__*/ defineComponent({
const rightButtonsTsx = __UNI_FEATURE_NAVIGATIONBAR_BUTTONS__
? createButtonsTsx(buttons.right)
: []
const type = navigationBar.type || 'default'
const placeholderTsx = type !== 'transparent' && type !== 'float' && (
<div
class={{
'uni-placeholder': true,
'uni-placeholder-titlePenetrate': navigationBar.titlePenetrate,
}}
></div>
)
return (
<uni-page-head uni-page-head-type={navigationBar.type}>
<uni-page-head uni-page-head-type={type}>
<div ref={headRef} class={clazz.value} style={style.value}>
<div class="uni-page-head-hd">
{backButtonTsx}
......@@ -67,6 +76,7 @@ export default /*#__PURE__*/ defineComponent({
{createPageHeadBdTsx(navigationBar, searchInput)}
<div class="uni-page-head-ft">{...rightButtonsTsx}</div>
</div>
{placeholderTsx}
</uni-page-head>
)
}
......
......@@ -5,18 +5,38 @@ export function initMixin(app: App) {
// 目前使用mixin实现,稍后应调整为不依赖options的方案
app.mixin({
created(this: ComponentPublicInstance) {
if (isApp(this)) {
this.__isApp = isApp(this)
this.__isPage = !this.__isApp && isPage(this)
if (this.__isApp) {
initApp(this)
} else if (isPage(this)) {
} else if (this.__isPage) {
initPage(this)
this.$callHook('onLoad', {})
this.__isVisible = true
this.$callHook('onShow')
}
},
mounted() {
if (isPage(this)) {
if (this.__isPage) {
this.$callHook('onReady')
}
},
beforeActivate() {
if (this.__isPage && !this.__isVisible) {
this.$callHook('onShow')
}
},
beforeDeactivate() {
if (this.__isPage) {
this.__isVisible = false
this.$callHook('onHide')
}
},
beforeUnmount() {
// TODO 目前onUnload时机不对,比前一个页面的onShow要晚
if (this.__isPage) {
this.$callHook('onUnload')
}
},
})
}
import { computed, nextTick, VNode, ComponentPublicInstance } from 'vue'
import {
VNode,
nextTick,
computed,
ConcreteComponent,
ComponentPublicInstance,
} from 'vue'
import { useRoute, RouteLocationNormalizedLoaded } from 'vue-router'
import { usePageMeta } from './provide'
const SEP = '$$'
const currentPages: Page.PageInstance[] = []
const currentPagesMap = new Map<number, Page.PageInstance>()
export function getCurrentPages() {
return currentPages
function pruneCurrentPages() {
currentPagesMap.forEach((page, id) => {
if (((page as unknown) as ComponentPublicInstance).$.isUnmounted) {
currentPagesMap.delete(id)
}
})
}
export function getCurrentPages(isAll: boolean = false) {
pruneCurrentPages() // TODO 目前页面unmounted时机较晚,前一个页面onShow里边调用getCurrentPages,可能还会获取到上一个准备被销毁的页面
return [...currentPagesMap.values()]
}
let id = (history.state && history.state.__id__) || 1
......@@ -49,43 +64,64 @@ function initPublicPage(route: RouteLocationNormalizedLoaded) {
}
export function initPage(vm: ComponentPublicInstance) {
currentPages.push((vm as unknown) as Page.PageInstance)
const route = vm.$route
;(vm as any).$page = initPublicPage(route)
}
// TODO
// https://github.com/vuejs/rfcs/pull/284
// https://github.com/vuejs/vue-next/pull/3414
function routeCache(
key: string,
cache: Map<string, VNode>,
pruneCacheEntry: (key: string) => void
) {
const pageId = parseInt(key.split(SEP)[1])
if (!pageId) {
return
}
nextTick(() => {
// prune post-render after `current` has been updated
const keys = cache.keys()
for (const key of keys) {
const cPageId = parseInt(key.split(SEP)[1])
if (cPageId && cPageId > pageId) {
pruneCacheEntry(key)
}
}
console.log('customKeepAlive', JSON.stringify([...cache.keys()]))
})
currentPagesMap.set(vm.$page.id, (vm as unknown) as Page.PageInstance)
}
export function useKeepAliveRoute() {
const route = useRoute()
const routeKey = computed(
() => route.fullPath + '$$' + (history.state.__id__ || 1)
() => route.fullPath + SEP + (history.state.__id__ || 1)
)
return {
routeKey,
routeCache,
}
}
// https://github.com/vuejs/rfcs/pull/284
// https://github.com/vuejs/vue-next/pull/3414
type CacheKey = string | number | ConcreteComponent
interface KeepAliveCache {
get(key: CacheKey): VNode | void
set(key: CacheKey, value: VNode): void
delete(key: CacheKey): void
forEach(
fn: (value: VNode, key: CacheKey, map: Map<CacheKey, VNode>) => void,
thisArg?: any
): void
pruneCacheEntry?: (cached: VNode) => void
}
const pageCacheMap = new Map<CacheKey, VNode>()
const routeCache: KeepAliveCache = {
get(key) {
return pageCacheMap.get(key)
},
set(key, value) {
pruneRouteCache(key as string)
pageCacheMap.set(key, value)
},
delete(key) {
pageCacheMap.delete(key)
},
forEach(fn) {
pageCacheMap.forEach(fn)
},
}
function pruneRouteCache(key: string) {
const pageId = parseInt(key.split(SEP)[1])
if (!pageId) {
return
}
routeCache.forEach((vnode, key) => {
const cPageId = parseInt((key as string).split(SEP)[1])
if (cPageId && cPageId > pageId) {
routeCache.delete(key)
routeCache.pruneCacheEntry!(vnode)
nextTick(() => pruneCurrentPages())
}
})
}
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
__isApp: boolean
__isPage: boolean
__isUnload: boolean
__isVisible: boolean
$page: Page.PageInstance['$page']
}
}
import plugin from './framework/plugin'
export { plugin }
......
......@@ -16,9 +16,17 @@ body {
}
uni-app,
uni-page {
uni-page,
uni-page-wrapper,
uni-page-body {
position: relative;
display: block;
box-sizing: border-box;
width: 100%;
}
uni-app,
uni-page,
uni-page-wrapper {
height: 100%;
}
uni-navigator {
height: auto;
width: auto;
display: block;
cursor: pointer;
}
uni-navigator[hidden] {
display: none;
}
.navigator-hover {
background-color: rgba(0, 0, 0, 0.1);
opacity: 0.7;
}
......@@ -240,3 +240,9 @@ uni-page-head {
.uni-page-head-shadow-yellow::after {
background-image: url('https://cdn.dcloud.net.cn/img/shadow-yellow.png');
}
uni-page-head[uni-page-head-type='default'] ~ uni-page-wrapper {
height: calc(100% - 44px);
height: calc(100% - 44px - constant(safe-area-inset-top));
height: calc(100% - 44px - env(safe-area-inset-top));
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册