提交 b4dd3b38 编写于 作者: D DCloud_LXH

fix(ssr): picker

上级 54a38fdf
......@@ -38,7 +38,7 @@
</view>
<!-- #endif -->
<!-- <view class="uni-title uni-common-pl">时间选择器</view>
<view class="uni-title uni-common-pl">时间选择器</view>
<view class="uni-list">
<view class="uni-list-cell">
<view class="uni-list-cell-left"> 当前选择 </view>
......@@ -75,7 +75,7 @@
</picker>
</view>
</view>
</view> -->
</view>
<view class="uni-picker-tips">
注:选择当前时间 ±10 年之间的时间, 不在区间内不能选中
</view>
......@@ -122,7 +122,7 @@ export default {
methods: {
bindPickerChange: function (e) {
console.log("picker发送选择改变,携带值为:" + e.detail.value);
// this.index = e.detail.value;
this.index = e.detail.value;
},
bindMultiPickerColumnChange: function (e) {
console.log("修改的列为:" + e.detail.column + ",值为:" + e.detail.value);
......
......@@ -1245,8 +1245,8 @@ function formatApiArgs(args, options) {
function invokeSuccess(id, name, res) {
return invokeCallback(id, shared.extend(res || {}, { errMsg: name + ":ok" }));
}
function invokeFail(id, name, err) {
return invokeCallback(id, { errMsg: name + ":fail" + (err ? " " + err : "") });
function invokeFail(id, name, errMsg, errRes) {
return invokeCallback(id, Object.assign({ errMsg: name + ":fail" + (errMsg ? " " + errMsg : "") }, errRes));
}
function beforeInvokeApi(name, args, protocol, options) {
if (process.env.NODE_ENV !== "production") {
......@@ -1272,7 +1272,7 @@ function wrapperTaskApi(name, fn, protocol, options) {
}
return fn(args, {
resolve: (res) => invokeSuccess(id, name, res),
reject: (err) => invokeFail(id, name, err)
reject: (errMsg2, errRes) => invokeFail(id, name, errMsg2, errRes)
});
};
}
......@@ -1594,31 +1594,9 @@ function wrapper(canvas) {
canvas.height = canvas.offsetHeight * pixelRatio;
canvas.getContext("2d").__hidpi__ = true;
}
let isHidpi = false;
function initHidpi() {
if (isHidpi) {
return;
}
isHidpi = true;
const proto = CanvasRenderingContext2D.prototype;
proto.drawImageByCanvas = function(_super) {
return function(canvas, srcx, srcy, srcw, srch, desx, desy, desw, desh, isScale) {
if (!this.__hidpi__) {
return _super.apply(this, arguments);
}
srcx *= pixelRatio;
srcy *= pixelRatio;
srcw *= pixelRatio;
srch *= pixelRatio;
desx *= pixelRatio;
desy *= pixelRatio;
desw = isScale ? desw * pixelRatio : desw;
desh = isScale ? desh * pixelRatio : desh;
_super.call(this, canvas, srcx, srcy, srcw, srch, desx, desy, desw, desh);
};
}(proto.drawImage);
}
const initHidpiOnce = /* @__PURE__ */ uniShared.once(initHidpi);
const initHidpiOnce = /* @__PURE__ */ uniShared.once(() => {
return void 0;
});
function $getRealPath(src) {
return src ? getRealPath(src) : src;
}
......@@ -7654,13 +7632,10 @@ var index$7 = /* @__PURE__ */ defineBuiltInComponent({
inheritAttrs: false,
name: "WebView",
props: props$7,
setup(props2, {
attrs
}) {
setup(props2) {
Invoke();
const rootRef = vue.ref(null);
const iframeRef = vue.ref(null);
const _resize = useWebViewSize(rootRef, iframeRef);
vue.ref(null);
const {
$attrs,
$excludeAttrs,
......@@ -7668,6 +7643,7 @@ var index$7 = /* @__PURE__ */ defineBuiltInComponent({
} = useAttrs({
excludeListeners: true
});
let _resize;
return () => {
return vue.createVNode(vue.Fragment, null, [vue.createVNode("uni-web-view", vue.mergeProps($listeners.value, $excludeAttrs.value, {
"ref": rootRef
......@@ -7675,37 +7651,10 @@ var index$7 = /* @__PURE__ */ defineBuiltInComponent({
default: () => [vue.createVNode(ResizeSensor, {
"onResize": _resize
}, null, 8, ["onResize"])]
}, 16), vue.createVNode(vue.Teleport, {
"to": "body"
}, {
default: () => [vue.createVNode("iframe", vue.mergeProps({
"ref": iframeRef,
"src": getRealPath(props2.src)
}, $attrs.value), null, 16, ["src"])]
})]);
}, 16)]);
};
}
});
function useWebViewSize(rootRef, iframeRef) {
const _resize = () => {
const {
top,
left,
width,
height
} = rootRef.value.getBoundingClientRect();
iframeRef.value && uniShared.updateElementStyle(iframeRef.value, {
position: "absolute",
display: "block",
border: "0",
top: top + "px",
left: left + "px",
width: width + "px",
height: height + "px"
});
};
return _resize;
}
const props$6 = {
id: {
type: [Number, String],
......@@ -8792,6 +8741,7 @@ var index$3 = /* @__PURE__ */ defineBuiltInComponent({
const pickerRef = vue.ref(null);
const selectRef = vue.ref(null);
const inputRef = vue.ref(null);
const pickerRender = vue.ref(false);
const {
state,
rangeArray
......@@ -8845,7 +8795,7 @@ var index$3 = /* @__PURE__ */ defineBuiltInComponent({
}, booleanAttrs, {
"onClick": withWebEvent(_show)
}), {
default: () => [vue.createVNode("div", {
default: () => [pickerRender.value ? vue.createVNode("div", {
"ref": pickerRef,
"class": ["uni-picker-container", `uni-${mode2}-${selectorTypeComputed.value}`],
"onWheel": onEventPrevent,
......@@ -8906,7 +8856,7 @@ var index$3 = /* @__PURE__ */ defineBuiltInComponent({
}
}, [typeof item === "object" ? item[rangeKey] || "" : item], 10, ["onClick"]))], 40, ["onWheel", "onTouchmove"]), vue.createVNode("div", {
"style": popupStyle.triangle
}, null, 4)], 6) : null], 40, ["onWheel", "onTouchmove"]), vue.createVNode("div", null, [slots.default && slots.default()]), system.value ? vue.createVNode("div", {
}, null, 4)], 6) : null], 40, ["onWheel", "onTouchmove"]) : null, vue.createVNode("div", null, [slots.default && slots.default()]), system.value ? vue.createVNode("div", {
"class": "uni-picker-system",
"onMousemove": withWebEvent(_fixInputPosition)
}, [vue.createVNode("input", {
......
import { isFunction, extend, hyphenate, isPlainObject, isString, isArray, hasOwn, isObject, capitalize, toRawType, makeMap as makeMap$1, isPromise, invokeArrayFns as invokeArrayFns$1 } from "@vue/shared";
import { once, passive, normalizeTarget, isBuiltInComponent, initCustomDataset, invokeArrayFns, SCHEME_RE, DATA_RE, getCustomDataset, callOptions, PRIMARY_COLOR, removeLeadingSlash, getLen, debounce, NAVBAR_HEIGHT, parseQuery, ON_REACH_BOTTOM_DISTANCE, decodedQuery, WEB_INVOKE_APPSERVICE, updateElementStyle, addFont, scrollTo, RESPONSIVE_MIN_WIDTH, formatDateTime } from "@dcloudio/uni-shared";
import { openBlock, createBlock, mergeProps, createVNode, toDisplayString, withModifiers, getCurrentInstance, defineComponent, ref, provide, computed, watch, onUnmounted, inject, onBeforeUnmount, reactive, onActivated, onMounted, nextTick, onBeforeMount, withDirectives, vShow, shallowRef, watchEffect, isVNode, Fragment, markRaw, createTextVNode, injectHook, onBeforeActivate, onBeforeDeactivate, renderList, onDeactivated, Teleport, createApp, Transition, withCtx, KeepAlive, resolveDynamicComponent, renderSlot } from "vue";
import { openBlock, createBlock, mergeProps, createVNode, toDisplayString, withModifiers, getCurrentInstance, defineComponent, ref, provide, computed, watch, onUnmounted, inject, onBeforeUnmount, reactive, onActivated, onMounted, nextTick, onBeforeMount, withDirectives, vShow, shallowRef, watchEffect, isVNode, Fragment, markRaw, createTextVNode, injectHook, onBeforeActivate, onBeforeDeactivate, renderList, onDeactivated, createApp, Transition, withCtx, KeepAlive, resolveDynamicComponent, renderSlot } from "vue";
import { initVueI18n, LOCALE_EN, LOCALE_ES, LOCALE_FR, LOCALE_ZH_HANS, LOCALE_ZH_HANT } from "@dcloudio/uni-i18n";
import { useRoute, createRouter, createWebHistory, createWebHashHistory, useRouter, isNavigationFailure, RouterView } from "vue-router";
var subscriber = {
......@@ -694,7 +694,7 @@ var safeAreaInsets = {
onChange,
offChange
};
var out = safeAreaInsets;
var D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out = safeAreaInsets;
const onEventPrevent = /* @__PURE__ */ withModifiers(() => {
}, ["prevent"]);
const onEventStop = /* @__PURE__ */ withModifiers(() => {
......@@ -706,10 +706,10 @@ function getWindowOffset() {
const left = parseInt(style.getPropertyValue("--window-left"));
const right = parseInt(style.getPropertyValue("--window-right"));
return {
top: top ? top + out.top : 0,
bottom: bottom ? bottom + out.bottom : 0,
left: left ? left + out.left : 0,
right: right ? right + out.right : 0
top: top ? top + D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out.top : 0,
bottom: bottom ? bottom + D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out.bottom : 0,
left: left ? left + D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out.left : 0,
right: right ? right + D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out.right : 0
};
}
function updateCssVar(cssVars) {
......@@ -2350,8 +2350,8 @@ function formatApiArgs(args, options) {
function invokeSuccess(id2, name, res) {
return invokeCallback(id2, extend(res || {}, { errMsg: name + ":ok" }));
}
function invokeFail(id2, name, err) {
return invokeCallback(id2, { errMsg: name + ":fail" + (err ? " " + err : "") });
function invokeFail(id2, name, errMsg, errRes) {
return invokeCallback(id2, Object.assign({ errMsg: name + ":fail" + (errMsg ? " " + errMsg : "") }, errRes));
}
function beforeInvokeApi(name, args, protocol, options) {
if (process.env.NODE_ENV !== "production") {
......@@ -2413,7 +2413,7 @@ function wrapperTaskApi(name, fn, protocol, options) {
}
return fn(args, {
resolve: (res) => invokeSuccess(id2, name, res),
reject: (err) => invokeFail(id2, name, err)
reject: (errMsg2, errRes) => invokeFail(id2, name, errMsg2, errRes)
});
};
}
......@@ -4834,7 +4834,8 @@ const API_SHOW_TOAST = "showToast";
const SHOW_TOAST_ICON = [
"success",
"loading",
"none"
"none",
"error"
];
const ShowToastProtocol = {
title: String,
......@@ -5879,7 +5880,9 @@ function initHidpi() {
}(proto.drawImage);
}
}
const initHidpiOnce = /* @__PURE__ */ once(initHidpi);
const initHidpiOnce = /* @__PURE__ */ once(() => {
return initHidpi();
});
function $getRealPath(src) {
return src ? getRealPath(src) : src;
}
......@@ -12988,7 +12991,7 @@ function normalizePageMeta(pageMeta) {
let offset = rpx2px(refreshOptions.offset);
const { type } = navigationBar;
if (type !== "transparent" && type !== "none") {
offset += NAVBAR_HEIGHT + out.top;
offset += NAVBAR_HEIGHT + D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out.top;
}
refreshOptions.offset = offset;
refreshOptions.height = rpx2px(refreshOptions.height);
......@@ -14320,13 +14323,10 @@ var index$7 = /* @__PURE__ */ defineBuiltInComponent({
inheritAttrs: false,
name: "WebView",
props: props$e,
setup(props2, {
attrs: attrs2
}) {
setup(props2) {
Invoke();
const rootRef = ref(null);
const iframeRef = ref(null);
const _resize = useWebViewSize(rootRef, iframeRef);
const {
$attrs,
$excludeAttrs,
......@@ -14334,6 +14334,25 @@ var index$7 = /* @__PURE__ */ defineBuiltInComponent({
} = useAttrs({
excludeListeners: true
});
let _resize;
const renderIframe = () => {
const iframe = document.createElement("iframe");
watchEffect(() => {
for (const key in $attrs.value) {
if (Object.prototype.hasOwnProperty.call($attrs.value, key)) {
const attr2 = $attrs.value[key];
iframe[key] = attr2;
}
}
});
watchEffect(() => {
iframe.src = getRealPath(props2.src);
});
document.body.appendChild(iframe);
iframeRef.value = iframe;
_resize = useWebViewSize(rootRef, iframeRef);
};
renderIframe();
onMounted(() => {
_resize();
});
......@@ -14343,6 +14362,9 @@ var index$7 = /* @__PURE__ */ defineBuiltInComponent({
onDeactivated(() => {
iframeRef.value && (iframeRef.value.style.display = "none");
});
onBeforeUnmount(() => {
document.body.removeChild(iframeRef.value);
});
return () => {
return createVNode(Fragment, null, [createVNode("uni-web-view", mergeProps($listeners.value, $excludeAttrs.value, {
"ref": rootRef
......@@ -14350,14 +14372,7 @@ var index$7 = /* @__PURE__ */ defineBuiltInComponent({
default: () => [createVNode(ResizeSensor, {
"onResize": _resize
}, null, 8, ["onResize"])]
}, 16), createVNode(Teleport, {
"to": "body"
}, {
default: () => [createVNode("iframe", mergeProps({
"ref": iframeRef,
"src": getRealPath(props2.src)
}, $attrs.value), null, 16, ["src"])]
})]);
}, 16)]);
};
}
});
......@@ -15193,7 +15208,7 @@ const getSystemInfoSync = /* @__PURE__ */ defineSyncApi("getSystemInfoSync", ()
const windowWidth = getWindowWidth(screenWidth);
let windowHeight = window.innerHeight;
const language = navigator.language;
const statusBarHeight = out.top;
const statusBarHeight = D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out.top;
let osname;
let osversion;
let model;
......@@ -15306,12 +15321,12 @@ const getSystemInfoSync = /* @__PURE__ */ defineSyncApi("getSystemInfoSync", ()
const system = `${osname} ${osversion}`;
const platform = osname.toLocaleLowerCase();
const safeArea = {
left: out.left,
right: windowWidth - out.right,
top: out.top,
bottom: windowHeight - out.bottom,
width: windowWidth - out.left - out.right,
height: windowHeight - out.top - out.bottom
left: D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out.left,
right: windowWidth - D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out.right,
top: D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out.top,
bottom: windowHeight - D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out.bottom,
width: windowWidth - D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out.left - D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out.right,
height: windowHeight - D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out.top - D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out.bottom
};
const { top: windowTop, bottom: windowBottom } = getWindowOffset();
windowHeight -= windowTop;
......@@ -15331,10 +15346,10 @@ const getSystemInfoSync = /* @__PURE__ */ defineSyncApi("getSystemInfoSync", ()
model,
safeArea,
safeAreaInsets: {
top: out.top,
right: out.right,
bottom: out.bottom,
left: out.left
top: D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out.top,
right: D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out.right,
bottom: D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out.bottom,
left: D__DCloud_local_git_uniAppNext_node_modules_safeAreaInsets_out.left
}
};
});
......@@ -17431,11 +17446,24 @@ var Toast = /* @__PURE__ */ defineComponent({
}
});
function useToastIcon(props2) {
const Icon = computed(() => props2.icon === "success" ? createVNode(createSvgIconVNode(ICON_PATH_SUCCESS_NO_CIRCLE, "#fff", 38), {
class: ToastIconClassName
}) : props2.icon === "loading" ? createVNode("i", {
"class": [ToastIconClassName, "uni-loading"]
}, null, 2) : null);
const Icon = computed(() => {
switch (props2.icon) {
case "success":
return createVNode(createSvgIconVNode(ICON_PATH_SUCCESS_NO_CIRCLE, "#fff", 38), {
class: ToastIconClassName
});
case "error":
return createVNode(createSvgIconVNode(ICON_PATH_WARN, "#fff", 38), {
class: ToastIconClassName
});
case "loading":
return createVNode("i", {
"class": [ToastIconClassName, "uni-loading"]
}, null, 2);
default:
return null;
}
});
return {
Icon
};
......@@ -19535,6 +19563,7 @@ var index$3 = /* @__PURE__ */ defineBuiltInComponent({
const pickerRef = ref(null);
const selectRef = ref(null);
const inputRef = ref(null);
const pickerRender = ref(false);
const {
state: state2,
rangeArray
......@@ -19570,6 +19599,9 @@ var index$3 = /* @__PURE__ */ defineBuiltInComponent({
onBeforeUnmount(() => {
pickerRef.value && pickerRef.value.remove();
});
onMounted(() => {
pickerRender.value = true;
});
return () => {
let _slot2;
const {
......@@ -19591,7 +19623,7 @@ var index$3 = /* @__PURE__ */ defineBuiltInComponent({
}, booleanAttrs, {
"onClick": withWebEvent(_show)
}), {
default: () => [createVNode("div", {
default: () => [pickerRender.value ? createVNode("div", {
"ref": pickerRef,
"class": ["uni-picker-container", `uni-${mode2}-${selectorTypeComputed.value}`],
"onWheel": onEventPrevent,
......@@ -19652,7 +19684,7 @@ var index$3 = /* @__PURE__ */ defineBuiltInComponent({
}
}, [typeof item === "object" ? item[rangeKey] || "" : item], 10, ["onClick"]))], 40, ["onWheel", "onTouchmove"]), createVNode("div", {
"style": popupStyle.triangle
}, null, 4)], 6) : null], 40, ["onWheel", "onTouchmove"]), createVNode("div", null, [slots.default && slots.default()]), system.value ? createVNode("div", {
}, null, 4)], 6) : null], 40, ["onWheel", "onTouchmove"]) : null, createVNode("div", null, [slots.default && slots.default()]), system.value ? createVNode("div", {
"class": "uni-picker-system",
"onMousemove": withWebEvent(_fixInputPosition)
}, [createVNode("input", {
......
......@@ -218,6 +218,7 @@ export default /*#__PURE__*/ defineBuiltInComponent({
const pickerRef: HTMLRef = ref(null)
const selectRef: HTMLRef = ref(null)
const inputRef: HTMLRef = ref(null)
const pickerRender = ref(false) // 防止ssr渲染的时候语言报错
const { state, rangeArray } = usePickerState(props)
const trigger = useCustomEvent<EmitEvent<typeof emit>>(rootRef, emit)
const {
......@@ -265,6 +266,10 @@ export default /*#__PURE__*/ defineBuiltInComponent({
pickerRef.value && pickerRef.value.remove()
})
onMounted(() => {
pickerRender.value = true
})
return () => {
const { visible, contentVisible, valueArray, popupStyle, valueSync } =
state
......@@ -277,93 +282,95 @@ export default /*#__PURE__*/ defineBuiltInComponent({
{...booleanAttrs}
onClick={withWebEvent(_show)}
>
<div
ref={pickerRef}
class="uni-picker-container"
// @ts-ignore
class={`uni-${mode}-${selectorTypeComputed.value}`}
onWheel={onEventPrevent}
onTouchmove={onEventPrevent}
>
<Transition name="uni-fade">
<div
v-show={visible}
class="uni-mask uni-picker-mask"
onClick={withWebEvent(_cancel)}
onMousemove={_fixInputPosition}
/>
</Transition>
{!system.value ? (
<div
class={{ 'uni-picker-toggle': visible }}
// @ts-ignore
class="uni-picker-custom"
style={popupStyle.content}
>
<div class="uni-picker-header" onClick={onEventStop}>
<div
class="uni-picker-action uni-picker-action-cancel"
onClick={withWebEvent(_cancel)}
>
{t('uni.picker.cancel')}
</div>
<div
class="uni-picker-action uni-picker-action-confirm"
onClick={_change}
>
{t('uni.picker.done')}
</div>
</div>
{contentVisible ? (
<PickerView
value={_l10nColumn(valueArray)}
class="uni-picker-content"
// @ts-ignore
onChange={_pickerViewChange}
>
{renderList(
_l10nColumn(rangeArray.value as []),
(rangeItem, index0) => (
<PickerViewColumn key={index0}>
{renderList(rangeItem, (item, index) => (
<div key={index} class="uni-picker-item">
{typeof item === 'object'
? item[rangeKey] || ''
: _l10nItem(item, index0)}
</div>
))}
</PickerViewColumn>
)
)}
</PickerView>
) : null}
{pickerRender.value ? (
<div
ref={pickerRef}
class="uni-picker-container"
// @ts-ignore
class={`uni-${mode}-${selectorTypeComputed.value}`}
onWheel={onEventPrevent}
onTouchmove={onEventPrevent}
>
<Transition name="uni-fade">
<div
ref={selectRef}
class="uni-picker-select"
onWheel={onEventStop}
onTouchmove={onEventStop}
v-show={visible}
class="uni-mask uni-picker-mask"
onClick={withWebEvent(_cancel)}
onMousemove={_fixInputPosition}
/>
</Transition>
{!system.value ? (
<div
class={{ 'uni-picker-toggle': visible }}
// @ts-ignore
class="uni-picker-custom"
style={popupStyle.content}
>
{renderList(rangeArray.value[0], (item, index) => (
<div class="uni-picker-header" onClick={onEventStop}>
<div
key={index}
class="uni-picker-item"
// @ts-ignore
class={{ selected: valueArray[0] === index }}
onClick={() => {
valueArray[0] = index
_change()
}}
class="uni-picker-action uni-picker-action-cancel"
onClick={withWebEvent(_cancel)}
>
{typeof item === 'object'
? (item as any)[rangeKey] || ''
: item}
{t('uni.picker.cancel')}
</div>
))}
<div
class="uni-picker-action uni-picker-action-confirm"
onClick={_change}
>
{t('uni.picker.done')}
</div>
</div>
{contentVisible ? (
<PickerView
value={_l10nColumn(valueArray)}
class="uni-picker-content"
// @ts-ignore
onChange={_pickerViewChange}
>
{renderList(
_l10nColumn(rangeArray.value as []),
(rangeItem, index0) => (
<PickerViewColumn key={index0}>
{renderList(rangeItem, (item, index) => (
<div key={index} class="uni-picker-item">
{typeof item === 'object'
? item[rangeKey] || ''
: _l10nItem(item, index0)}
</div>
))}
</PickerViewColumn>
)
)}
</PickerView>
) : null}
<div
ref={selectRef}
class="uni-picker-select"
onWheel={onEventStop}
onTouchmove={onEventStop}
>
{renderList(rangeArray.value[0], (item, index) => (
<div
key={index}
class="uni-picker-item"
// @ts-ignore
class={{ selected: valueArray[0] === index }}
onClick={() => {
valueArray[0] = index
_change()
}}
>
{typeof item === 'object'
? (item as any)[rangeKey] || ''
: item}
</div>
))}
</div>
<div style={popupStyle.triangle} />
</div>
<div style={popupStyle.triangle} />
</div>
) : null}
</div>
) : null}
</div>
) : null}
<div>{slots.default && slots.default()}</div>
{system.value ? (
<div
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册