uni.mp.esm.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  1. import { SLOT_DEFAULT_NAME, EventChannel, invokeArrayFns, MINI_PROGRAM_PAGE_RUNTIME_HOOKS, ON_LOAD, ON_SHOW, ON_HIDE, ON_UNLOAD, ON_RESIZE, ON_TAB_ITEM_TAP, ON_REACH_BOTTOM, ON_PULL_DOWN_REFRESH, ON_ADD_TO_FAVORITES, isUniLifecycleHook, ON_READY, ON_LAUNCH, ON_ERROR, ON_THEME_CHANGE, ON_PAGE_NOT_FOUND, ON_UNHANDLE_REJECTION, customizeEvent, addLeadingSlash, stringifyQuery } from '@dcloudio/uni-shared';
  2. import { isArray, isFunction, hasOwn, extend, hyphenate, isPlainObject, isObject } from '@vue/shared';
  3. import { ref, nextTick, findComponentPropsData, toRaw, updateProps, hasQueueJob, invalidateJob, devtoolsComponentAdded, getExposeProxy, pruneComponentPropsCache } from 'vue';
  4. import { normalizeLocale, LOCALE_EN } from '@dcloudio/uni-i18n';
  5. const MP_METHODS = [
  6. 'createSelectorQuery',
  7. 'createIntersectionObserver',
  8. 'selectAllComponents',
  9. 'selectComponent',
  10. ];
  11. function createEmitFn(oldEmit, ctx) {
  12. return function emit(event, ...args) {
  13. const scope = ctx.$scope;
  14. if (scope && event) {
  15. const detail = { __args__: args };
  16. // 百度小程序,快手小程序,自定义组件不能绑定动态事件
  17. {
  18. detail.__ins__ = scope;
  19. }
  20. {
  21. scope.triggerEvent(event, detail);
  22. }
  23. }
  24. return oldEmit.apply(this, [event, ...args]);
  25. };
  26. }
  27. function initBaseInstance(instance, options) {
  28. const ctx = instance.ctx;
  29. // mp
  30. ctx.mpType = options.mpType; // @deprecated
  31. ctx.$mpType = options.mpType;
  32. ctx.$mpPlatform = "mp-xhs";
  33. ctx.$scope = options.mpInstance;
  34. // TODO @deprecated
  35. ctx.$mp = {};
  36. if (__VUE_OPTIONS_API__) {
  37. ctx._self = {};
  38. }
  39. // slots
  40. instance.slots = {};
  41. if (isArray(options.slots) && options.slots.length) {
  42. options.slots.forEach((name) => {
  43. instance.slots[name] = true;
  44. });
  45. if (instance.slots[SLOT_DEFAULT_NAME]) {
  46. instance.slots.default = true;
  47. }
  48. }
  49. ctx.getOpenerEventChannel = function () {
  50. if (!this.__eventChannel__) {
  51. this.__eventChannel__ = new EventChannel();
  52. }
  53. return this.__eventChannel__;
  54. };
  55. ctx.$hasHook = hasHook;
  56. ctx.$callHook = callHook;
  57. // $emit
  58. instance.emit = createEmitFn(instance.emit, ctx);
  59. }
  60. function initComponentInstance(instance, options) {
  61. initBaseInstance(instance, options);
  62. const ctx = instance.ctx;
  63. MP_METHODS.forEach((method) => {
  64. ctx[method] = function (...args) {
  65. const mpInstance = ctx.$scope;
  66. if (mpInstance && mpInstance[method]) {
  67. return mpInstance[method].apply(mpInstance, args);
  68. }
  69. };
  70. });
  71. }
  72. function initMocks(instance, mpInstance, mocks) {
  73. const ctx = instance.ctx;
  74. mocks.forEach((mock) => {
  75. if (hasOwn(mpInstance, mock)) {
  76. instance[mock] = ctx[mock] = mpInstance[mock];
  77. }
  78. });
  79. }
  80. function hasHook(name) {
  81. const hooks = this.$[name];
  82. if (hooks && hooks.length) {
  83. return true;
  84. }
  85. return false;
  86. }
  87. function callHook(name, args) {
  88. if (name === 'mounted') {
  89. callHook.call(this, 'bm'); // beforeMount
  90. this.$.isMounted = true;
  91. name = 'm';
  92. }
  93. {
  94. if (name === 'onLoad' &&
  95. args &&
  96. args.__id__ &&
  97. isFunction(xhs.getEventChannel)) {
  98. this.__eventChannel__ = xhs.getEventChannel(args.__id__);
  99. delete args.__id__;
  100. }
  101. }
  102. const hooks = this.$[name];
  103. return hooks && invokeArrayFns(hooks, args);
  104. }
  105. const PAGE_INIT_HOOKS = [
  106. ON_LOAD,
  107. ON_SHOW,
  108. ON_HIDE,
  109. ON_UNLOAD,
  110. ON_RESIZE,
  111. ON_TAB_ITEM_TAP,
  112. ON_REACH_BOTTOM,
  113. ON_PULL_DOWN_REFRESH,
  114. ON_ADD_TO_FAVORITES,
  115. // 'onReady', // lifetimes.ready
  116. // 'onPageScroll', // 影响性能,开发者手动注册
  117. // 'onShareTimeline', // 右上角菜单,开发者手动注册
  118. // 'onShareAppMessage' // 右上角菜单,开发者手动注册
  119. ];
  120. function findHooks(vueOptions, hooks = new Set()) {
  121. if (vueOptions) {
  122. Object.keys(vueOptions).forEach((name) => {
  123. if (isUniLifecycleHook(name, vueOptions[name])) {
  124. hooks.add(name);
  125. }
  126. });
  127. if (__VUE_OPTIONS_API__) {
  128. const { extends: extendsOptions, mixins } = vueOptions;
  129. if (mixins) {
  130. mixins.forEach((mixin) => findHooks(mixin, hooks));
  131. }
  132. if (extendsOptions) {
  133. findHooks(extendsOptions, hooks);
  134. }
  135. }
  136. }
  137. return hooks;
  138. }
  139. function initHook(mpOptions, hook, excludes) {
  140. if (excludes.indexOf(hook) === -1 && !hasOwn(mpOptions, hook)) {
  141. mpOptions[hook] = function (args) {
  142. return this.$vm && this.$vm.$callHook(hook, args);
  143. };
  144. }
  145. }
  146. const EXCLUDE_HOOKS = [ON_READY];
  147. function initHooks(mpOptions, hooks, excludes = EXCLUDE_HOOKS) {
  148. hooks.forEach((hook) => initHook(mpOptions, hook, excludes));
  149. }
  150. function initUnknownHooks(mpOptions, vueOptions, excludes = EXCLUDE_HOOKS) {
  151. findHooks(vueOptions).forEach((hook) => initHook(mpOptions, hook, excludes));
  152. }
  153. function initRuntimeHooks(mpOptions, runtimeHooks) {
  154. if (!runtimeHooks) {
  155. return;
  156. }
  157. const hooks = Object.keys(MINI_PROGRAM_PAGE_RUNTIME_HOOKS);
  158. hooks.forEach((hook) => {
  159. if (runtimeHooks & MINI_PROGRAM_PAGE_RUNTIME_HOOKS[hook]) {
  160. initHook(mpOptions, hook, []);
  161. }
  162. });
  163. }
  164. const HOOKS = [
  165. ON_SHOW,
  166. ON_HIDE,
  167. ON_ERROR,
  168. ON_THEME_CHANGE,
  169. ON_PAGE_NOT_FOUND,
  170. ON_UNHANDLE_REJECTION,
  171. ];
  172. function parseApp(instance, parseAppOptions) {
  173. const internalInstance = instance.$;
  174. if (__VUE_PROD_DEVTOOLS__) {
  175. // 定制 App 的 $children
  176. Object.defineProperty(internalInstance.ctx, '$children', {
  177. get() {
  178. return getCurrentPages().map((page) => page.$vm);
  179. },
  180. });
  181. }
  182. const appOptions = {
  183. globalData: (instance.$options && instance.$options.globalData) || {},
  184. $vm: instance,
  185. onLaunch(options) {
  186. this.$vm = instance; // 飞书小程序可能会把 AppOptions 序列化,导致 $vm 对象部分属性丢失
  187. const ctx = internalInstance.ctx;
  188. if (this.$vm && ctx.$scope) {
  189. // 已经初始化过了,主要是为了百度,百度 onShow 在 onLaunch 之前
  190. return;
  191. }
  192. initBaseInstance(internalInstance, {
  193. mpType: 'app',
  194. mpInstance: this,
  195. slots: [],
  196. });
  197. ctx.globalData = this.globalData;
  198. instance.$callHook(ON_LAUNCH, options);
  199. },
  200. };
  201. const { onError } = internalInstance;
  202. if (onError) {
  203. internalInstance.appContext.config.errorHandler = (err) => {
  204. instance.$callHook(ON_ERROR, err);
  205. };
  206. }
  207. initLocale(instance);
  208. const vueOptions = instance.$.type;
  209. initHooks(appOptions, HOOKS);
  210. initUnknownHooks(appOptions, vueOptions);
  211. if (__VUE_OPTIONS_API__) {
  212. const methods = vueOptions.methods;
  213. methods && extend(appOptions, methods);
  214. }
  215. if (parseAppOptions) {
  216. parseAppOptions.parse(appOptions);
  217. }
  218. return appOptions;
  219. }
  220. function initCreateApp(parseAppOptions) {
  221. return function createApp(vm) {
  222. return App(parseApp(vm, parseAppOptions));
  223. };
  224. }
  225. function initCreateSubpackageApp(parseAppOptions) {
  226. return function createApp(vm) {
  227. const appOptions = parseApp(vm, parseAppOptions);
  228. const app = isFunction(getApp) &&
  229. getApp({
  230. allowDefault: true,
  231. });
  232. if (!app)
  233. return;
  234. vm.$.ctx.$scope = app;
  235. const globalData = app.globalData;
  236. if (globalData) {
  237. Object.keys(appOptions.globalData).forEach((name) => {
  238. if (!hasOwn(globalData, name)) {
  239. globalData[name] = appOptions.globalData[name];
  240. }
  241. });
  242. }
  243. Object.keys(appOptions).forEach((name) => {
  244. if (!hasOwn(app, name)) {
  245. app[name] = appOptions[name];
  246. }
  247. });
  248. initAppLifecycle(appOptions, vm);
  249. if (process.env.UNI_SUBPACKAGE) {
  250. (xhs.$subpackages || (xhs.$subpackages = {}))[process.env.UNI_SUBPACKAGE] = {
  251. $vm: vm,
  252. };
  253. }
  254. };
  255. }
  256. function initAppLifecycle(appOptions, vm) {
  257. if (isFunction(appOptions.onLaunch)) {
  258. const args = xhs.getLaunchOptionsSync && xhs.getLaunchOptionsSync();
  259. appOptions.onLaunch(args);
  260. }
  261. if (isFunction(appOptions.onShow) && xhs.onAppShow) {
  262. xhs.onAppShow((args) => {
  263. vm.$callHook('onShow', args);
  264. });
  265. }
  266. if (isFunction(appOptions.onHide) && xhs.onAppHide) {
  267. xhs.onAppHide((args) => {
  268. vm.$callHook('onHide', args);
  269. });
  270. }
  271. }
  272. function initLocale(appVm) {
  273. const locale = ref(normalizeLocale(xhs.getSystemInfoSync().language) || LOCALE_EN);
  274. Object.defineProperty(appVm, '$locale', {
  275. get() {
  276. return locale.value;
  277. },
  278. set(v) {
  279. locale.value = v;
  280. },
  281. });
  282. }
  283. function initVueIds(vueIds, mpInstance) {
  284. if (!vueIds) {
  285. return;
  286. }
  287. const ids = vueIds.split(',');
  288. const len = ids.length;
  289. if (len === 1) {
  290. mpInstance._$vueId = ids[0];
  291. }
  292. else if (len === 2) {
  293. mpInstance._$vueId = ids[0];
  294. mpInstance._$vuePid = ids[1];
  295. }
  296. }
  297. const EXTRAS = ['externalClasses'];
  298. function initExtraOptions(miniProgramComponentOptions, vueOptions) {
  299. EXTRAS.forEach((name) => {
  300. if (hasOwn(vueOptions, name)) {
  301. miniProgramComponentOptions[name] = vueOptions[name];
  302. }
  303. });
  304. }
  305. function initWxsCallMethods(methods, wxsCallMethods) {
  306. if (!isArray(wxsCallMethods)) {
  307. return;
  308. }
  309. wxsCallMethods.forEach((callMethod) => {
  310. methods[callMethod] = function (args) {
  311. return this.$vm[callMethod](args);
  312. };
  313. });
  314. }
  315. function selectAllComponents(mpInstance, selector, $refs) {
  316. const components = mpInstance.selectAllComponents(selector);
  317. components.forEach((component) => {
  318. const ref = component.properties.uR;
  319. $refs[ref] = component.$vm || component;
  320. });
  321. }
  322. function initRefs(instance, mpInstance) {
  323. Object.defineProperty(instance, 'refs', {
  324. get() {
  325. const $refs = {};
  326. selectAllComponents(mpInstance, '.r', $refs);
  327. const forComponents = mpInstance.selectAllComponents('.r-i-f');
  328. forComponents.forEach((component) => {
  329. const ref = component.properties.uR;
  330. if (!ref) {
  331. return;
  332. }
  333. if (!$refs[ref]) {
  334. $refs[ref] = [];
  335. }
  336. $refs[ref].push(component.$vm || component);
  337. });
  338. return $refs;
  339. },
  340. });
  341. }
  342. function findVmByVueId(instance, vuePid) {
  343. // 标准 vue3 中 没有 $children,定制了内核
  344. const $children = instance.$children;
  345. // 优先查找直属(反向查找:https://github.com/dcloudio/uni-app/issues/1200)
  346. for (let i = $children.length - 1; i >= 0; i--) {
  347. const childVm = $children[i];
  348. if (childVm.$scope._$vueId === vuePid) {
  349. return childVm;
  350. }
  351. }
  352. // 反向递归查找
  353. let parentVm;
  354. for (let i = $children.length - 1; i >= 0; i--) {
  355. parentVm = findVmByVueId($children[i], vuePid);
  356. if (parentVm) {
  357. return parentVm;
  358. }
  359. }
  360. }
  361. const EVENT_OPTS = 'eO';
  362. /**
  363. * 需要搭配:
  364. * ./componentInstance/index.ts:24 triggerEvent 时传递 __ins__
  365. * ./componentProps.ts:49 增加 properties eO
  366. * @param this
  367. * @param event
  368. * @returns
  369. */
  370. function handleEvent(event) {
  371. const { type, currentTarget: { dataset }, detail: { __ins__ }, } = event;
  372. let methodName = type;
  373. // 快手小程序的 __l 方法也会走此处逻辑,但没有 __ins__
  374. if (__ins__) {
  375. // 自定义事件,通过 triggerEvent 传递 __ins__
  376. let eventObj = {};
  377. try {
  378. // https://github.com/dcloudio/uni-app/issues/3647
  379. // 通过字符串序列化解决百度小程序修改对象不触发组件properties变化的Bug
  380. eventObj = JSON.parse(__ins__.properties[EVENT_OPTS]);
  381. }
  382. catch (e) { }
  383. methodName = resolveMethodName(type, eventObj);
  384. }
  385. else if (dataset && dataset[EVENT_OPTS]) {
  386. // 快手小程序 input 等内置组件的 input 事件也会走此逻辑,所以从 dataset 中读取
  387. methodName = resolveMethodName(type, dataset[EVENT_OPTS]);
  388. }
  389. if (!this[methodName]) {
  390. return console.warn(type + ' not found');
  391. }
  392. this[methodName](event);
  393. }
  394. function resolveMethodName(name, obj) {
  395. return obj[name] || obj[hyphenate(name)];
  396. }
  397. function nextSetDataTick(mpInstance, fn) {
  398. // 随便设置一个字段来触发回调(部分平台必须有字段才可以,比如头条)
  399. mpInstance.setData({ r1: 1 }, () => fn());
  400. }
  401. function initSetRef(mpInstance) {
  402. if (!mpInstance._$setRef) {
  403. mpInstance._$setRef = (fn) => {
  404. nextTick(() => nextSetDataTick(mpInstance, fn));
  405. };
  406. }
  407. }
  408. const builtInProps = [
  409. // 百度小程序,快手小程序自定义组件不支持绑定动态事件,动态dataset,故通过props传递事件信息
  410. // event-opts
  411. 'eO',
  412. // 组件 ref
  413. 'uR',
  414. // 组件 ref-in-for
  415. 'uRIF',
  416. // 组件 id
  417. 'uI',
  418. // 组件类型 m: 小程序组件
  419. 'uT',
  420. // 组件 props
  421. 'uP',
  422. // 小程序不能直接定义 $slots 的 props,所以通过 vueSlots 转换到 $slots
  423. 'uS',
  424. ];
  425. function initDefaultProps(options, isBehavior = false) {
  426. const properties = {};
  427. if (!isBehavior) {
  428. // 均不指定类型,避免微信小程序 property received type-uncompatible value 警告
  429. builtInProps.forEach((name) => {
  430. properties[name] = {
  431. type: null,
  432. value: '',
  433. };
  434. });
  435. // 小程序不能直接定义 $slots 的 props,所以通过 vueSlots 转换到 $slots
  436. properties.uS = {
  437. type: null,
  438. value: [],
  439. observer: function (newVal) {
  440. const $slots = Object.create(null);
  441. newVal &&
  442. newVal.forEach((slotName) => {
  443. $slots[slotName] = true;
  444. });
  445. this.setData({
  446. $slots,
  447. });
  448. },
  449. };
  450. }
  451. if (options.behaviors) {
  452. // wx://form-field
  453. if (options.behaviors.includes('xhs://form-field')) {
  454. if (!options.properties || !options.properties.name) {
  455. properties.name = {
  456. type: null,
  457. value: '',
  458. };
  459. }
  460. if (!options.properties || !options.properties.value) {
  461. properties.value = {
  462. type: null,
  463. value: '',
  464. };
  465. }
  466. }
  467. }
  468. return properties;
  469. }
  470. function initVirtualHostProps(options) {
  471. const properties = {};
  472. return properties;
  473. }
  474. /**
  475. *
  476. * @param mpComponentOptions
  477. * @param isBehavior
  478. */
  479. function initProps(mpComponentOptions) {
  480. if (!mpComponentOptions.properties) {
  481. mpComponentOptions.properties = {};
  482. }
  483. extend(mpComponentOptions.properties, initDefaultProps(mpComponentOptions), initVirtualHostProps(mpComponentOptions.options));
  484. }
  485. function findPropsData(properties, isPage) {
  486. return ((isPage
  487. ? findPagePropsData(properties)
  488. : findComponentPropsData(properties.uP)) || {});
  489. }
  490. function findPagePropsData(properties) {
  491. const propsData = {};
  492. if (isPlainObject(properties)) {
  493. Object.keys(properties).forEach((name) => {
  494. if (builtInProps.indexOf(name) === -1) {
  495. propsData[name] = properties[name];
  496. }
  497. });
  498. }
  499. return propsData;
  500. }
  501. function initFormField(vm) {
  502. // 同步 form-field 的 name,value 值
  503. const vueOptions = vm.$options;
  504. if (isArray(vueOptions.behaviors) &&
  505. vueOptions.behaviors.includes('uni://form-field')) {
  506. vm.$watch('modelValue', () => {
  507. vm.$scope &&
  508. vm.$scope.setData({
  509. name: vm.name,
  510. value: vm.modelValue,
  511. });
  512. }, {
  513. immediate: true,
  514. });
  515. }
  516. }
  517. function initData(_) {
  518. return {};
  519. }
  520. function initPropsObserver(componentOptions) {
  521. const observe = function observe() {
  522. const up = this.properties.uP;
  523. if (!up) {
  524. return;
  525. }
  526. if (this.$vm) {
  527. updateComponentProps(up, this.$vm.$);
  528. }
  529. else if (this.properties.uT === 'm') {
  530. // 小程序组件
  531. updateMiniProgramComponentProperties(up, this);
  532. }
  533. };
  534. {
  535. componentOptions.properties.uP.observer = observe;
  536. }
  537. }
  538. function updateMiniProgramComponentProperties(up, mpInstance) {
  539. const prevProps = mpInstance.properties;
  540. const nextProps = findComponentPropsData(up) || {};
  541. if (hasPropsChanged(prevProps, nextProps, false)) {
  542. mpInstance.setData(nextProps);
  543. }
  544. }
  545. function updateComponentProps(up, instance) {
  546. const prevProps = toRaw(instance.props);
  547. const nextProps = findComponentPropsData(up) || {};
  548. if (hasPropsChanged(prevProps, nextProps)) {
  549. updateProps(instance, nextProps, prevProps, false);
  550. if (hasQueueJob(instance.update)) {
  551. invalidateJob(instance.update);
  552. }
  553. {
  554. instance.update();
  555. }
  556. }
  557. }
  558. function hasPropsChanged(prevProps, nextProps, checkLen = true) {
  559. const nextKeys = Object.keys(nextProps);
  560. if (checkLen && nextKeys.length !== Object.keys(prevProps).length) {
  561. return true;
  562. }
  563. for (let i = 0; i < nextKeys.length; i++) {
  564. const key = nextKeys[i];
  565. if (nextProps[key] !== prevProps[key]) {
  566. return true;
  567. }
  568. }
  569. return false;
  570. }
  571. function initBehaviors(vueOptions) {
  572. const vueBehaviors = vueOptions.behaviors;
  573. let vueProps = vueOptions.props;
  574. if (!vueProps) {
  575. vueOptions.props = vueProps = [];
  576. }
  577. const behaviors = [];
  578. if (isArray(vueBehaviors)) {
  579. vueBehaviors.forEach((behavior) => {
  580. behaviors.push(behavior.replace('uni://', 'xhs://'));
  581. if (behavior === 'uni://form-field') {
  582. if (isArray(vueProps)) {
  583. vueProps.push('name');
  584. vueProps.push('modelValue');
  585. }
  586. else {
  587. vueProps.name = {
  588. type: String,
  589. default: '',
  590. };
  591. vueProps.modelValue = {
  592. type: [String, Number, Boolean, Array, Object, Date],
  593. default: '',
  594. };
  595. }
  596. }
  597. });
  598. }
  599. return behaviors;
  600. }
  601. function applyOptions(componentOptions, vueOptions) {
  602. componentOptions.data = initData();
  603. componentOptions.behaviors = initBehaviors(vueOptions);
  604. }
  605. function parseComponent(vueOptions, { parse, mocks, isPage, initRelation, handleLink, initLifetimes, }) {
  606. vueOptions = vueOptions.default || vueOptions;
  607. const options = {
  608. multipleSlots: true,
  609. // styleIsolation: 'apply-shared',
  610. addGlobalClass: true,
  611. pureDataPattern: /^uP$/,
  612. };
  613. if (isArray(vueOptions.mixins)) {
  614. vueOptions.mixins.forEach((item) => {
  615. if (isObject(item.options)) {
  616. extend(options, item.options);
  617. }
  618. });
  619. }
  620. if (vueOptions.options) {
  621. extend(options, vueOptions.options);
  622. }
  623. const mpComponentOptions = {
  624. options,
  625. lifetimes: initLifetimes({ mocks, isPage, initRelation, vueOptions }),
  626. pageLifetimes: {
  627. show() {
  628. if (__VUE_PROD_DEVTOOLS__) {
  629. devtoolsComponentAdded(this.$vm.$);
  630. }
  631. this.$vm && this.$vm.$callHook('onPageShow');
  632. },
  633. hide() {
  634. this.$vm && this.$vm.$callHook('onPageHide');
  635. },
  636. resize(size) {
  637. this.$vm && this.$vm.$callHook('onPageResize', size);
  638. },
  639. },
  640. methods: {
  641. __l: handleLink,
  642. },
  643. };
  644. if (__VUE_OPTIONS_API__) {
  645. applyOptions(mpComponentOptions, vueOptions);
  646. }
  647. initProps(mpComponentOptions);
  648. initPropsObserver(mpComponentOptions);
  649. initExtraOptions(mpComponentOptions, vueOptions);
  650. initWxsCallMethods(mpComponentOptions.methods, vueOptions.wxsCallMethods);
  651. if (parse) {
  652. parse(mpComponentOptions, { handleLink });
  653. }
  654. return mpComponentOptions;
  655. }
  656. function initCreateComponent(parseOptions) {
  657. return function createComponent(vueComponentOptions) {
  658. return Component(parseComponent(vueComponentOptions, parseOptions));
  659. };
  660. }
  661. let $createComponentFn;
  662. let $destroyComponentFn;
  663. function getAppVm() {
  664. if (process.env.UNI_MP_PLUGIN) {
  665. return xhs.$vm;
  666. }
  667. if (process.env.UNI_SUBPACKAGE) {
  668. return xhs.$subpackages[process.env.UNI_SUBPACKAGE].$vm;
  669. }
  670. return getApp().$vm;
  671. }
  672. function $createComponent(initialVNode, options) {
  673. if (!$createComponentFn) {
  674. $createComponentFn = getAppVm().$createComponent;
  675. }
  676. const proxy = $createComponentFn(initialVNode, options);
  677. return getExposeProxy(proxy.$) || proxy;
  678. }
  679. function $destroyComponent(instance) {
  680. if (!$destroyComponentFn) {
  681. $destroyComponentFn = getAppVm().$destroyComponent;
  682. }
  683. return $destroyComponentFn(instance);
  684. }
  685. const MPPage = Page;
  686. const MPComponent = Component;
  687. function initTriggerEvent(mpInstance) {
  688. const oldTriggerEvent = mpInstance.triggerEvent;
  689. const newTriggerEvent = function (event, ...args) {
  690. return oldTriggerEvent.apply(mpInstance, [customizeEvent(event), ...args]);
  691. };
  692. // 京东小程序triggerEvent为只读属性
  693. try {
  694. mpInstance.triggerEvent = newTriggerEvent;
  695. }
  696. catch (error) {
  697. mpInstance._triggerEvent = newTriggerEvent;
  698. }
  699. }
  700. function initMiniProgramHook(name, options, isComponent) {
  701. const oldHook = options[name];
  702. if (!oldHook) {
  703. options[name] = function () {
  704. initTriggerEvent(this);
  705. };
  706. }
  707. else {
  708. options[name] = function (...args) {
  709. initTriggerEvent(this);
  710. return oldHook.apply(this, args);
  711. };
  712. }
  713. }
  714. Page = function (options) {
  715. initMiniProgramHook(ON_LOAD, options);
  716. return MPPage(options);
  717. };
  718. Component = function (options) {
  719. initMiniProgramHook('created', options);
  720. // 小程序组件
  721. const isVueComponent = options.properties && options.properties.uP;
  722. if (!isVueComponent) {
  723. initProps(options);
  724. initPropsObserver(options);
  725. }
  726. return MPComponent(options);
  727. };
  728. // @ts-ignore
  729. function initLifetimes({ mocks, isPage, initRelation, vueOptions, }) {
  730. return {
  731. attached() {
  732. // 微信 和 QQ 不需要延迟 setRef
  733. {
  734. initSetRef(this);
  735. }
  736. let properties = this.properties;
  737. initVueIds(properties.uI, this);
  738. const relationOptions = {
  739. vuePid: this._$vuePid,
  740. };
  741. // 处理父子关系
  742. initRelation(this, relationOptions);
  743. // 初始化 vue 实例
  744. const mpInstance = this;
  745. const isMiniProgramPage = isPage(mpInstance);
  746. let propsData = properties;
  747. this.$vm = $createComponent({
  748. type: vueOptions,
  749. props: findPropsData(propsData, isMiniProgramPage),
  750. }, {
  751. mpType: isMiniProgramPage ? 'page' : 'component',
  752. mpInstance,
  753. slots: properties.uS || {},
  754. parentComponent: relationOptions.parent && relationOptions.parent.$,
  755. onBeforeSetup(instance, options) {
  756. initRefs(instance, mpInstance);
  757. initMocks(instance, mpInstance, mocks);
  758. initComponentInstance(instance, options);
  759. },
  760. });
  761. if (!isMiniProgramPage) {
  762. initFormField(this.$vm);
  763. }
  764. },
  765. ready() {
  766. // 当组件 props 默认值为 true,初始化时传入 false 会导致 created,ready 触发, 但 attached 不触发
  767. // https://developers.weixin.qq.com/community/develop/doc/00066ae2844cc0f8eb883e2a557800
  768. if (this.$vm) {
  769. {
  770. nextSetDataTick(this, () => {
  771. this.$vm.$callHook('mounted');
  772. this.$vm.$callHook(ON_READY);
  773. });
  774. }
  775. }
  776. },
  777. detached() {
  778. if (this.$vm) {
  779. pruneComponentPropsCache(this.$vm.$.uid);
  780. $destroyComponent(this.$vm);
  781. }
  782. },
  783. };
  784. }
  785. function handleLink(event) {
  786. // detail 是微信,value 是百度(dipatch)
  787. const detail = (event.detail ||
  788. event.value);
  789. const vuePid = detail.vuePid;
  790. let parentVm;
  791. if (vuePid) {
  792. parentVm = findVmByVueId(this.$vm, vuePid);
  793. }
  794. if (!parentVm) {
  795. parentVm = this.$vm;
  796. }
  797. detail.parent = parentVm;
  798. }
  799. xhs.canIUse('component2');
  800. const mocks$1 = ['nodeId', 'componentId', 'componentPath'];
  801. function initSpecialMethods(mpInstance) {
  802. if (!mpInstance.$vm) {
  803. return;
  804. }
  805. let path = mpInstance.is || mpInstance.route;
  806. if (!path) {
  807. return;
  808. }
  809. if (path.indexOf('/') === 0) {
  810. path = path.slice(1);
  811. }
  812. const specialMethods = xhs.specialMethods && xhs.specialMethods[path];
  813. if (specialMethods) {
  814. specialMethods.forEach((method) => {
  815. if (isFunction(mpInstance.$vm[method])) {
  816. mpInstance[method] = function (event) {
  817. if (hasOwn(event, 'markerId')) {
  818. event.detail = typeof event.detail === 'object' ? event.detail : {};
  819. event.detail.markerId = event.markerId;
  820. }
  821. // TODO normalizeEvent
  822. mpInstance.$vm[method](event);
  823. };
  824. }
  825. });
  826. }
  827. }
  828. function createVueComponent(mpType, mpInstance, vueOptions, parent) {
  829. return $createComponent({
  830. type: vueOptions,
  831. props: findPropsData(mpInstance.props, mpType === 'page'),
  832. }, {
  833. mpType,
  834. mpInstance,
  835. slots: mpInstance.props.uS || {},
  836. parentComponent: parent && parent.$,
  837. onBeforeSetup(instance, options) {
  838. initRefs(instance, mpInstance);
  839. initMocks(instance, mpInstance, mocks$1);
  840. initComponentInstance(instance, options);
  841. },
  842. });
  843. }
  844. function initCreatePage() {
  845. return function createPage(vueOptions) {
  846. vueOptions = vueOptions.default || vueOptions;
  847. const pageOptions = {
  848. onLoad(query) {
  849. this.options = query;
  850. this.$page = {
  851. fullPath: addLeadingSlash(this.route + stringifyQuery(query)),
  852. };
  853. // 初始化 vue 实例
  854. this.props = query;
  855. },
  856. onShow() {
  857. if (__VUE_PROD_DEVTOOLS__) {
  858. devtoolsComponentAdded(this.$vm.$);
  859. }
  860. this.$vm = createVueComponent('page', this, vueOptions);
  861. this.$vm.$callHook('mounted');
  862. this.$vm.$callHook(ON_LOAD, this.options);
  863. initSpecialMethods(this);
  864. if (this.$vm) {
  865. this.$vm.$callHook(ON_SHOW);
  866. }
  867. },
  868. onReady() {
  869. setTimeout(() => {
  870. this.$vm.$callHook(ON_READY);
  871. }, 50);
  872. },
  873. onUnload() {
  874. if (this.$vm) {
  875. this.$vm.$callHook(ON_UNLOAD);
  876. $destroyComponent(this.$vm);
  877. }
  878. },
  879. __l: handleLink,
  880. __e: handleEvent,
  881. };
  882. if (isPlainObject(vueOptions.events)) {
  883. extend(pageOptions.events, vueOptions.events);
  884. }
  885. if (__VUE_OPTIONS_API__) {
  886. pageOptions.data = initData();
  887. }
  888. initHooks(pageOptions, PAGE_INIT_HOOKS);
  889. initUnknownHooks(pageOptions, vueOptions);
  890. initRuntimeHooks(pageOptions, vueOptions.__runtimeHooks);
  891. initWxsCallMethods(pageOptions, vueOptions.wxsCallMethods);
  892. return Page(pageOptions);
  893. };
  894. }
  895. const mocks = ['nodeId', 'componentPath', 'componentId'];
  896. function isPage(mpInstance) {
  897. return !!mpInstance.route;
  898. }
  899. function initRelation(mpInstance, detail) {
  900. mpInstance.triggerEvent('__l', detail);
  901. }
  902. function parse(componentOptions) {
  903. const methods = componentOptions.methods;
  904. methods.__e = handleEvent;
  905. methods.__l = handleLink;
  906. }
  907. var parseComponentOptions = /*#__PURE__*/Object.freeze({
  908. __proto__: null,
  909. handleLink: handleLink,
  910. initLifetimes: initLifetimes,
  911. initRelation: initRelation,
  912. isPage: isPage,
  913. mocks: mocks,
  914. parse: parse
  915. });
  916. const createApp = initCreateApp();
  917. const createPage = initCreatePage();
  918. const createComponent = initCreateComponent(parseComponentOptions);
  919. const createSubpackageApp = initCreateSubpackageApp();
  920. xhs.EventChannel = EventChannel;
  921. xhs.createApp = global.createApp = createApp;
  922. xhs.createPage = createPage;
  923. xhs.createComponent = createComponent;
  924. xhs.createSubpackageApp = global.createSubpackageApp =
  925. createSubpackageApp;
  926. export { createApp, createComponent, createPage, createSubpackageApp };