提交 405e1137 编写于 作者: Q qiang

chore: Merge branch 'next' of github.com:dcloudio/uni-app into next

# Conflicts:
#	packages/uni-cloud/package.json
......@@ -8,6 +8,7 @@ export * from './service/context/createMapContext'
export * from './service/context/canvas'
export * from './service/ui/createIntersectionObserver'
export * from './service/ui/createMediaQueryObserver'
export * from './service/ui/createSelectorQuery'
export * from './service/ui/createAnimation'
export * from './service/ui/tabBar'
......
import { ComponentPublicInstance } from 'vue'
import { isFunction } from '@vue/shared'
import { getCurrentPageVm, getPageIdByVm } from '@dcloudio/uni-core'
import { defineSyncApi } from '../../helpers/api'
import {
addMediaQueryObserver,
removeMediaQueryObserver,
} from '@dcloudio/uni-platform'
export interface AddMediaQueryObserverArgs {
reqId: number
component: ComponentPublicInstance
options: UniApp.DescriptorOptions
callback: WechatMiniprogram.MediaQueryObserverObserveCallback
}
export interface RemoveMediaQueryObserverArgs {
reqId: number
component: ComponentPublicInstance
}
let reqComponentObserverId = 1
class ServiceMediaQueryObserver {
private _reqId?: number
private _pageId: number
private _component: ComponentPublicInstance
constructor(component: ComponentPublicInstance) {
this._pageId = component.$page && component.$page.id
this._component = component
}
observe(
options: UniApp.DescriptorOptions,
callback: WechatMiniprogram.MediaQueryObserverObserveCallback
) {
if (!isFunction(callback)) {
return
}
this._reqId = reqComponentObserverId++
addMediaQueryObserver(
{
reqId: this._reqId,
component: this._component,
options,
callback,
},
this._pageId
)
}
disconnect() {
this._reqId &&
removeMediaQueryObserver(
{
reqId: this._reqId,
component: this._component,
},
this._pageId
)
}
}
export const createMediaQueryObserver = defineSyncApi<
typeof uni.createMediaQueryObserver
>('createMediaQueryObserver', (context?: any) => {
if (context && !getPageIdByVm(context)) {
context = null
}
if (context) {
return new ServiceMediaQueryObserver(context)
}
return new ServiceMediaQueryObserver(getCurrentPageVm()!)
})
......@@ -11,7 +11,7 @@ import Input from './input/index'
import Label from './label/index'
import MovableArea from './movable-area/index'
import MovableView from './movable-view/index'
import Navigator from './navigator/index.vue'
import Navigator from './navigator'
import PickerView from './picker-view/index'
import PickerViewColumn from './picker-view-column/index'
import Progress from './progress/index'
......
import { useHover } from '../../helpers/useHover'
import { defineBuiltInComponent } from '@dcloudio/uni-components'
const OPEN_TYPES = [
'navigate',
'redirect',
'switchTab',
'reLaunch',
'navigateBack',
]
const props = {
hoverClass: {
type: String,
default: 'navigator-hover',
},
url: {
type: String,
default: '',
},
openType: {
type: String,
default: 'navigate',
validator(value: unknown) {
return Boolean(~OPEN_TYPES.indexOf(value as string))
},
},
delta: {
type: Number,
default: 1,
},
hoverStartTime: {
type: [Number, String],
default: 50,
},
hoverStayTime: {
type: [Number, String],
default: 600,
},
exists: {
type: String,
default: '',
},
hoverStopPropagation: {
type: Boolean,
default: false,
},
}
export default /*#__PURE__*/ defineBuiltInComponent({
name: 'Navigator',
compatConfig: {
MODE: 3,
},
props,
setup(props, { slots }) {
const { hovering, binding } = useHover(props)
function onClick($event: MouseEvent) {
if (props.openType !== 'navigateBack' && !props.url) {
console.error(
'<navigator/> should have url attribute when using navigateTo, redirectTo, reLaunch or switchTab'
)
return
}
switch (props.openType) {
case 'navigate':
uni.navigateTo({
url: props.url,
})
break
case 'redirect':
uni.redirectTo({
url: props.url,
// @ts-ignore
exists: props.exists,
})
break
case 'switchTab':
uni.switchTab({
url: props.url,
})
break
case 'reLaunch':
uni.reLaunch({
url: props.url,
})
break
case 'navigateBack':
uni.navigateBack({
delta: props.delta,
})
break
default:
break
}
}
return () => {
const { hoverClass } = props
const hasHoverClass = props.hoverClass && props.hoverClass !== 'none'
return (
<uni-navigator
class={hasHoverClass && hovering.value ? hoverClass : ''}
{...(hasHoverClass && binding)}
onClick={onClick}
>
{slots.default && slots.default()}
</uni-navigator>
)
}
},
})
<template>
<uni-navigator
v-if="hoverClass && hoverClass !== 'none'"
:class="[hovering ? hoverClass : '']"
v-bind="binding"
@click="_onClick"
>
<slot />
</uni-navigator>
<uni-navigator v-else @click="_onClick">
<slot />
</uni-navigator>
</template>
<script>
import { useHover } from "../../helpers/useHover";
const OPEN_TYPES = ["navigate", "redirect", "switchTab", "reLaunch", "navigateBack"];
export default {
name: "Navigator",
compatConfig: {
MODE: 3
},
props: {
hoverClass: {
type: String,
default: "navigator-hover",
},
url: {
type: String,
default: "",
},
openType: {
type: String,
default: "navigate",
validator(value) {
return ~OPEN_TYPES.indexOf(value);
},
},
delta: {
type: Number,
default: 1,
},
hoverStartTime: {
type: [Number, String],
default: 50,
},
hoverStayTime: {
type: [Number, String],
default: 600,
},
exists: {
type: String,
default: "",
},
hoverStopPropagation: {
type: Boolean,
default: false,
},
},
methods: {
_onClick($event) {
if (this.openType !== "navigateBack" && !this.url) {
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,
});
break;
case "redirect":
uni.redirectTo({
url: this.url,
exists: this.exists,
});
break;
case "switchTab":
uni.switchTab({
url: this.url,
});
break;
case "reLaunch":
uni.reLaunch({
url: this.url,
});
break;
case "navigateBack":
uni.navigateBack({
delta: this.delta,
});
break;
default:
break;
}
},
},
setup(props) {
const { hovering, binding } = useHover(props);
return {
hovering,
binding,
};
},
};
</script>
......@@ -20,6 +20,10 @@ export function createSelectorQuery(this: ComponentPublicInstance) {
return uni.createSelectorQuery().in(this)
}
export function createMediaQueryObserver(this: ComponentPublicInstance) {
return uni.createMediaQueryObserver(this)
}
export function createIntersectionObserver(
this: ComponentPublicInstance,
options: UniApp.CreateIntersectionObserverOptions
......
此差异已折叠。
此差异已折叠。
......@@ -7,6 +7,10 @@ export {
addIntersectionObserver,
removeIntersectionObserver,
} from '../service/api/ui/intersectionObserver'
export {
addMediaQueryObserver,
removeMediaQueryObserver,
} from '../service/api/ui/mediaQueryObserver'
export * from './saveImage'
export * from './constants'
export { getSameOriginUrl } from '../helpers/file'
......@@ -69,6 +69,7 @@ export {
arrayBufferToBase64,
base64ToArrayBuffer,
createIntersectionObserver,
createMediaQueryObserver,
createSelectorQuery,
createVideoContext,
createMapContext,
......
......@@ -22,6 +22,7 @@ export const redirectTo = defineAsyncApi<API_TYPE_REDIRECT_TO>(
API_REDIRECT_TO,
({ url }, { resolve, reject }) => {
return (
// TODO exists 属性未实现
removeLastPage(),
navigate(API_REDIRECT_TO, url).then(resolve).catch(reject)
)
......
import {
AddMediaQueryObserverArgs,
RemoveMediaQueryObserverArgs,
} from '@dcloudio/uni-api'
let mediaQueryObserver: MediaQueryList
let listener: (e: MediaQueryList) => void
// 拼接媒体查询条件
function handleMediaQueryStr($props: UniApp.DescriptorOptions) {
const mediaQueryArr = []
const propsMenu = [
'width',
'minWidth',
'maxWidth',
'height',
'minHeight',
'maxHeight',
'orientation',
]
for (const item of propsMenu) {
if (
item !== 'orientation' &&
$props[item as keyof UniApp.DescriptorOptions] &&
Number($props[item as keyof UniApp.DescriptorOptions] >= 0)
) {
mediaQueryArr.push(
`(${humpToLine(item)}: ${Number(
$props[item as keyof UniApp.DescriptorOptions]
)}px)`
)
}
if (item === 'orientation' && $props[item]) {
mediaQueryArr.push(`(${humpToLine(item)}: ${$props[item]})`)
}
}
const mediaQueryStr = mediaQueryArr.join(' and ')
return mediaQueryStr
}
function humpToLine(name: string) {
return name.replace(/([A-Z])/g, '-$1').toLowerCase()
}
// 请求媒体查询对象
export function addMediaQueryObserver(
{ reqId, component, options, callback }: AddMediaQueryObserverArgs,
_pageId: number
) {
// 创建一个媒体查询对象
mediaQueryObserver = window.matchMedia(handleMediaQueryStr(options))
// 创建一个监听器
listener = (observer) => callback(observer.matches as any)
listener(mediaQueryObserver) // 监听前执行一次媒体查询
mediaQueryObserver.addListener(listener as any)
}
// 销毁媒体查询对象
export function removeMediaQueryObserver(
{ reqId, component }: RemoveMediaQueryObserverArgs,
_pageId: number
) {
if (mediaQueryObserver) {
mediaQueryObserver.removeListener(listener as any) // 移除监听
}
}
import { ref } from 'vue'
import { getRealPath } from '@dcloudio/uni-platform'
import { useCustomEvent, EmitEvent } from '@dcloudio/uni-components'
import { defineBuiltInComponent } from '@dcloudio/uni-components'
export default /*#__PURE__*/ defineBuiltInComponent({
name: 'CoverImage',
compatConfig: {
MODE: 3,
},
props: {
src: {
type: String,
default: '',
},
},
emits: ['load', 'error'],
setup(props, { emit }) {
const root = ref(null)
const trigger = useCustomEvent<EmitEvent<typeof emit>>(root, emit)
function load($event: Event) {
trigger('load', $event)
}
function error($event: Event) {
trigger('error', $event)
}
return () => {
const { src } = props
return (
<uni-cover-image ref={root} src={src}>
<div class="uni-cover-image">
{src ? (
<img src={getRealPath(src)} onLoad={load} onError={error} />
) : null}
</div>
</uni-cover-image>
)
}
},
})
<template>
<uni-cover-image ref="root" :src="src">
<div class="uni-cover-image">
<img v-if="src" :src="getRealPath(src)" @load="_load" @error="_error" />
</div>
</uni-cover-image>
</template>
<script>
import { ref } from "vue";
import { getRealPath } from "@dcloudio/uni-platform";
import { useCustomEvent } from "@dcloudio/uni-components";
export default {
name: "CoverImage",
compatConfig: {
MODE: 3
},
props: {
src: {
type: String,
default: "",
},
},
methods: {
getRealPath,
_load($event) {
this.$trigger("load", $event);
},
_error($event) {
this.$trigger("error", $event);
},
},
mounted() {
this.$trigger = useCustomEvent({ value: this.root }, this.$emit);
},
setup() {
const root = ref(null);
return {
root,
};
},
};
</script>
import { ref, ExtractPropTypes, watch, onMounted } from 'vue'
import { defineBuiltInComponent } from '@dcloudio/uni-components'
const props = {
scrollTop: {
type: [String, Number],
default: 0,
},
}
type Props = ExtractPropTypes<typeof props>
export default /*#__PURE__*/ defineBuiltInComponent({
name: 'CoverView',
compatConfig: {
MODE: 3,
},
props,
setup(props, { slots }) {
const content = ref<HTMLElement | null>(null)
watch(
() => props.scrollTop,
(val) => {
setScrollTop(val)
}
)
function setScrollTop(val: Props['scrollTop']) {
let _content = content.value!
if (getComputedStyle(_content).overflowY === 'scroll') {
_content.scrollTop = _upx2pxNum(val)
}
}
function _upx2pxNum(val: Props['scrollTop']) {
let _val = String(val)
if (/\d+[ur]px$/i.test(_val)) {
_val.replace(/\d+[ur]px$/i, (text) => {
return String(uni.upx2px(parseFloat(text)))
})
}
return parseFloat(_val) || 0
}
onMounted(() => {
setScrollTop(props.scrollTop)
})
return () => {
return (
<uni-cover-view scroll-top={props.scrollTop}>
<div ref={content} class="uni-cover-view">
{slots.default && slots.default()}
</div>
</uni-cover-view>
)
}
},
})
<template>
<uni-cover-view :scroll-top="scrollTop">
<div ref="content" class="uni-cover-view">
<slot />
</div>
</uni-cover-view>
</template>
<script>
import { ref } from "vue";
export default {
name: "CoverView",
compatConfig: {
MODE: 3
},
props: {
scrollTop: {
type: [String, Number],
default: 0,
},
},
watch: {
scrollTop(val) {
this.setScrollTop(val);
},
},
mounted() {
this.setScrollTop(this.scrollTop);
},
methods: {
setScrollTop(val) {
var content = this.content;
if (getComputedStyle(content).overflowY === "scroll") {
content.scrollTop = this._upx2pxNum(val);
}
},
_upx2pxNum(val) {
if (/\d+[ur]px$/i.test(val)) {
val.replace(/\d+[ur]px$/i, (text) => {
return uni.upx2px(parseFloat(text));
});
}
return parseFloat(val) || 0;
},
},
setup() {
const content = ref(null);
return {
content,
};
},
};
</script>
\ No newline at end of file
import Video from './video/index'
import WebView from './web-view/index'
import Map from './map/index'
import CoverView from './cover-view/index.vue'
import CoverImage from './cover-image/index.vue'
import CoverView from './cover-view'
import CoverImage from './cover-image'
import Picker from './picker/index.vue'
export { Video, WebView, Map, CoverView, CoverImage, Picker }
......@@ -4,6 +4,8 @@ export function operateMap() {}
export function requestComponentInfo() {}
export function addIntersectionObserver() {}
export function removeIntersectionObserver() {}
export function addMediaQueryObserver() {}
export function removeMediaQueryObserver() {}
export function saveImage() {}
export function getSameOriginUrl() {}
export const TEMP_PATH = ''
......@@ -45,7 +45,7 @@ exports.fuzzyMatchTarget = (partialTargets, includeAllMatching) => {
}
})
if (matched.length) {
return matched
return matched.sort((a, b) => priority[b] - priority[a])
} else {
console.log()
console.error(
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册