uni.mp.esm.js 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121
  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, once, ON_LAUNCH, ON_ERROR, ON_THEME_CHANGE, ON_PAGE_NOT_FOUND, ON_UNHANDLE_REJECTION, addLeadingSlash, stringifyQuery, ON_INIT, customizeEvent } 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-baidu";
  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(swan.getEventChannel)) {
  98. this.__eventChannel__ = swan.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 findMixinRuntimeHooks = /*#__PURE__*/ once(() => {
  165. const runtimeHooks = [];
  166. const app = isFunction(getApp) && getApp({ allowDefault: true });
  167. if (app && app.$vm && app.$vm.$) {
  168. const mixins = app.$vm.$.appContext.mixins;
  169. if (isArray(mixins)) {
  170. const hooks = Object.keys(MINI_PROGRAM_PAGE_RUNTIME_HOOKS);
  171. mixins.forEach((mixin) => {
  172. hooks.forEach((hook) => {
  173. if (hasOwn(mixin, hook) && !runtimeHooks.includes(hook)) {
  174. runtimeHooks.push(hook);
  175. }
  176. });
  177. });
  178. }
  179. }
  180. return runtimeHooks;
  181. });
  182. function initMixinRuntimeHooks(mpOptions) {
  183. initHooks(mpOptions, findMixinRuntimeHooks());
  184. }
  185. const HOOKS = [
  186. ON_SHOW,
  187. ON_HIDE,
  188. ON_ERROR,
  189. ON_THEME_CHANGE,
  190. ON_PAGE_NOT_FOUND,
  191. ON_UNHANDLE_REJECTION,
  192. ];
  193. function parseApp(instance, parseAppOptions) {
  194. const internalInstance = instance.$;
  195. if (__VUE_PROD_DEVTOOLS__) {
  196. // 定制 App 的 $children
  197. Object.defineProperty(internalInstance.ctx, '$children', {
  198. get() {
  199. return getCurrentPages().map((page) => page.$vm);
  200. },
  201. });
  202. }
  203. const appOptions = {
  204. globalData: (instance.$options && instance.$options.globalData) || {},
  205. $vm: instance,
  206. onLaunch(options) {
  207. this.$vm = instance; // 飞书小程序可能会把 AppOptions 序列化,导致 $vm 对象部分属性丢失
  208. const ctx = internalInstance.ctx;
  209. if (this.$vm && ctx.$scope) {
  210. // 已经初始化过了,主要是为了百度,百度 onShow 在 onLaunch 之前
  211. return;
  212. }
  213. initBaseInstance(internalInstance, {
  214. mpType: 'app',
  215. mpInstance: this,
  216. slots: [],
  217. });
  218. ctx.globalData = this.globalData;
  219. instance.$callHook(ON_LAUNCH, options);
  220. },
  221. };
  222. const { onError } = internalInstance;
  223. if (onError) {
  224. internalInstance.appContext.config.errorHandler = (err) => {
  225. instance.$callHook(ON_ERROR, err);
  226. };
  227. }
  228. initLocale(instance);
  229. const vueOptions = instance.$.type;
  230. initHooks(appOptions, HOOKS);
  231. initUnknownHooks(appOptions, vueOptions);
  232. if (__VUE_OPTIONS_API__) {
  233. const methods = vueOptions.methods;
  234. methods && extend(appOptions, methods);
  235. }
  236. if (parseAppOptions) {
  237. parseAppOptions.parse(appOptions);
  238. }
  239. return appOptions;
  240. }
  241. function initCreateApp(parseAppOptions) {
  242. return function createApp(vm) {
  243. return App(parseApp(vm, parseAppOptions));
  244. };
  245. }
  246. function initCreateSubpackageApp(parseAppOptions) {
  247. return function createApp(vm) {
  248. const appOptions = parseApp(vm, parseAppOptions);
  249. const app = isFunction(getApp) &&
  250. getApp({
  251. allowDefault: true,
  252. });
  253. if (!app)
  254. return;
  255. vm.$.ctx.$scope = app;
  256. const globalData = app.globalData;
  257. if (globalData) {
  258. Object.keys(appOptions.globalData).forEach((name) => {
  259. if (!hasOwn(globalData, name)) {
  260. globalData[name] = appOptions.globalData[name];
  261. }
  262. });
  263. }
  264. Object.keys(appOptions).forEach((name) => {
  265. if (!hasOwn(app, name)) {
  266. app[name] = appOptions[name];
  267. }
  268. });
  269. initAppLifecycle(appOptions, vm);
  270. if (process.env.UNI_SUBPACKAGE) {
  271. (swan.$subpackages || (swan.$subpackages = {}))[process.env.UNI_SUBPACKAGE] = {
  272. $vm: vm,
  273. };
  274. }
  275. };
  276. }
  277. function initAppLifecycle(appOptions, vm) {
  278. if (isFunction(appOptions.onLaunch)) {
  279. const args = swan.getLaunchOptionsSync && swan.getLaunchOptionsSync();
  280. appOptions.onLaunch(args);
  281. }
  282. if (isFunction(appOptions.onShow) && swan.onAppShow) {
  283. swan.onAppShow((args) => {
  284. vm.$callHook('onShow', args);
  285. });
  286. }
  287. if (isFunction(appOptions.onHide) && swan.onAppHide) {
  288. swan.onAppHide((args) => {
  289. vm.$callHook('onHide', args);
  290. });
  291. }
  292. }
  293. function initLocale(appVm) {
  294. const locale = ref(normalizeLocale(swan.getSystemInfoSync().language) || LOCALE_EN);
  295. Object.defineProperty(appVm, '$locale', {
  296. get() {
  297. return locale.value;
  298. },
  299. set(v) {
  300. locale.value = v;
  301. },
  302. });
  303. }
  304. function initVueIds(vueIds, mpInstance) {
  305. if (!vueIds) {
  306. return;
  307. }
  308. const ids = vueIds.split(',');
  309. const len = ids.length;
  310. if (len === 1) {
  311. mpInstance._$vueId = ids[0];
  312. }
  313. else if (len === 2) {
  314. mpInstance._$vueId = ids[0];
  315. mpInstance._$vuePid = ids[1];
  316. }
  317. }
  318. const EXTRAS = ['externalClasses'];
  319. function initExtraOptions(miniProgramComponentOptions, vueOptions) {
  320. EXTRAS.forEach((name) => {
  321. if (hasOwn(vueOptions, name)) {
  322. miniProgramComponentOptions[name] = vueOptions[name];
  323. }
  324. });
  325. }
  326. function initWxsCallMethods(methods, wxsCallMethods) {
  327. if (!isArray(wxsCallMethods)) {
  328. return;
  329. }
  330. wxsCallMethods.forEach((callMethod) => {
  331. methods[callMethod] = function (args) {
  332. return this.$vm[callMethod](args);
  333. };
  334. });
  335. }
  336. function selectAllComponents(mpInstance, selector, $refs) {
  337. const components = mpInstance.selectAllComponents(selector);
  338. components.forEach((component) => {
  339. const ref = component.properties.uR;
  340. $refs[ref] = component.$vm || component;
  341. });
  342. }
  343. function initRefs(instance, mpInstance) {
  344. Object.defineProperty(instance, 'refs', {
  345. get() {
  346. const $refs = {};
  347. selectAllComponents(mpInstance, '.r', $refs);
  348. const forComponents = mpInstance.selectAllComponents('.r-i-f');
  349. forComponents.forEach((component) => {
  350. const ref = component.properties.uR;
  351. if (!ref) {
  352. return;
  353. }
  354. if (!$refs[ref]) {
  355. $refs[ref] = [];
  356. }
  357. $refs[ref].push(component.$vm || component);
  358. });
  359. return $refs;
  360. },
  361. });
  362. }
  363. function findVmByVueId(instance, vuePid) {
  364. // 标准 vue3 中 没有 $children,定制了内核
  365. const $children = instance.$children;
  366. // 优先查找直属(反向查找:https://github.com/dcloudio/uni-app/issues/1200)
  367. for (let i = $children.length - 1; i >= 0; i--) {
  368. const childVm = $children[i];
  369. if (childVm.$scope._$vueId === vuePid) {
  370. return childVm;
  371. }
  372. }
  373. // 反向递归查找
  374. let parentVm;
  375. for (let i = $children.length - 1; i >= 0; i--) {
  376. parentVm = findVmByVueId($children[i], vuePid);
  377. if (parentVm) {
  378. return parentVm;
  379. }
  380. }
  381. }
  382. const EVENT_OPTS = 'eO';
  383. /**
  384. * 需要搭配:
  385. * ./componentInstance/index.ts:24 triggerEvent 时传递 __ins__
  386. * ./componentProps.ts:49 增加 properties eO
  387. * @param this
  388. * @param event
  389. * @returns
  390. */
  391. function handleEvent(event) {
  392. const { type, currentTarget: { dataset }, detail: { __ins__ }, } = event;
  393. let methodName = type;
  394. // 快手小程序的 __l 方法也会走此处逻辑,但没有 __ins__
  395. if (__ins__) {
  396. // 自定义事件,通过 triggerEvent 传递 __ins__
  397. let eventObj = {};
  398. try {
  399. // https://github.com/dcloudio/uni-app/issues/3647
  400. // 通过字符串序列化解决百度小程序修改对象不触发组件properties变化的Bug
  401. eventObj = JSON.parse(__ins__.properties[EVENT_OPTS]);
  402. }
  403. catch (e) { }
  404. methodName = resolveMethodName(type, eventObj);
  405. }
  406. else if (dataset && dataset[EVENT_OPTS]) {
  407. // 快手小程序 input 等内置组件的 input 事件也会走此逻辑,所以从 dataset 中读取
  408. methodName = resolveMethodName(type, dataset[EVENT_OPTS]);
  409. }
  410. if (!this[methodName]) {
  411. return console.warn(type + ' not found');
  412. }
  413. this[methodName](event);
  414. }
  415. function resolveMethodName(name, obj) {
  416. return obj[name] || obj[hyphenate(name)];
  417. }
  418. function nextSetDataTick(mpInstance, fn) {
  419. // 随便设置一个字段来触发回调(部分平台必须有字段才可以,比如头条)
  420. mpInstance.setData({ r1: 1 }, () => fn());
  421. }
  422. function initSetRef(mpInstance) {
  423. if (!mpInstance._$setRef) {
  424. mpInstance._$setRef = (fn) => {
  425. nextTick(() => nextSetDataTick(mpInstance, fn));
  426. };
  427. }
  428. }
  429. const builtInProps = [
  430. // 百度小程序,快手小程序自定义组件不支持绑定动态事件,动态dataset,故通过props传递事件信息
  431. // event-opts
  432. 'eO',
  433. // 组件 ref
  434. 'uR',
  435. // 组件 ref-in-for
  436. 'uRIF',
  437. // 组件 id
  438. 'uI',
  439. // 组件类型 m: 小程序组件
  440. 'uT',
  441. // 组件 props
  442. 'uP',
  443. // 小程序不能直接定义 $slots 的 props,所以通过 vueSlots 转换到 $slots
  444. 'uS',
  445. ];
  446. function initDefaultProps(options, isBehavior = false) {
  447. const properties = {};
  448. if (!isBehavior) {
  449. // 均不指定类型,避免微信小程序 property received type-uncompatible value 警告
  450. builtInProps.forEach((name) => {
  451. properties[name] = {
  452. type: null,
  453. value: '',
  454. };
  455. });
  456. // 小程序不能直接定义 $slots 的 props,所以通过 vueSlots 转换到 $slots
  457. properties.uS = {
  458. type: null,
  459. value: [],
  460. observer: function (newVal) {
  461. const $slots = Object.create(null);
  462. newVal &&
  463. newVal.forEach((slotName) => {
  464. $slots[slotName] = true;
  465. });
  466. this.setData({
  467. $slots,
  468. });
  469. },
  470. };
  471. }
  472. if (options.behaviors) {
  473. // wx://form-field
  474. if (options.behaviors.includes('swan://form-field')) {
  475. if (!options.properties || !options.properties.name) {
  476. properties.name = {
  477. type: null,
  478. value: '',
  479. };
  480. }
  481. if (!options.properties || !options.properties.value) {
  482. properties.value = {
  483. type: null,
  484. value: '',
  485. };
  486. }
  487. }
  488. }
  489. return properties;
  490. }
  491. function initVirtualHostProps(options) {
  492. const properties = {};
  493. return properties;
  494. }
  495. /**
  496. *
  497. * @param mpComponentOptions
  498. * @param isBehavior
  499. */
  500. function initProps(mpComponentOptions) {
  501. if (!mpComponentOptions.properties) {
  502. mpComponentOptions.properties = {};
  503. }
  504. extend(mpComponentOptions.properties, initDefaultProps(mpComponentOptions), initVirtualHostProps(mpComponentOptions.options));
  505. }
  506. const PROP_TYPES = [String, Number, Boolean, Object, Array, null];
  507. function parsePropType(type, defaultValue) {
  508. // [String]=>String
  509. if (isArray(type) && type.length === 1) {
  510. return type[0];
  511. }
  512. {
  513. if (
  514. // [String,Boolean]=>Boolean
  515. defaultValue === false &&
  516. isArray(type) &&
  517. type.length === 2 &&
  518. type.indexOf(String) !== -1 &&
  519. type.indexOf(Boolean) !== -1) {
  520. return Boolean;
  521. }
  522. }
  523. return type;
  524. }
  525. function normalizePropType(type, defaultValue) {
  526. const res = parsePropType(type, defaultValue);
  527. return PROP_TYPES.indexOf(res) !== -1 ? res : null;
  528. }
  529. /**
  530. * 初始化页面 props,方便接收页面参数,类型均为String,默认值均为''
  531. * @param param
  532. * @param rawProps
  533. */
  534. function initPageProps({ properties }, rawProps) {
  535. if (isArray(rawProps)) {
  536. rawProps.forEach((key) => {
  537. properties[key] = {
  538. type: String,
  539. value: '',
  540. };
  541. });
  542. }
  543. else if (isPlainObject(rawProps)) {
  544. Object.keys(rawProps).forEach((key) => {
  545. const opts = rawProps[key];
  546. if (isPlainObject(opts)) {
  547. // title:{type:String,default:''}
  548. let value = opts.default;
  549. if (isFunction(value)) {
  550. value = value();
  551. }
  552. const type = opts.type;
  553. opts.type = normalizePropType(type, value);
  554. properties[key] = {
  555. type: opts.type,
  556. value,
  557. };
  558. }
  559. else {
  560. // content:String
  561. properties[key] = {
  562. type: normalizePropType(opts, null),
  563. };
  564. }
  565. });
  566. }
  567. }
  568. function findPropsData(properties, isPage) {
  569. return ((isPage
  570. ? findPagePropsData(properties)
  571. : findComponentPropsData(properties.uP)) || {});
  572. }
  573. function findPagePropsData(properties) {
  574. const propsData = {};
  575. if (isPlainObject(properties)) {
  576. Object.keys(properties).forEach((name) => {
  577. if (builtInProps.indexOf(name) === -1) {
  578. propsData[name] = properties[name];
  579. }
  580. });
  581. }
  582. return propsData;
  583. }
  584. function initFormField(vm) {
  585. // 同步 form-field 的 name,value 值
  586. const vueOptions = vm.$options;
  587. if (isArray(vueOptions.behaviors) &&
  588. vueOptions.behaviors.includes('uni://form-field')) {
  589. vm.$watch('modelValue', () => {
  590. vm.$scope &&
  591. vm.$scope.setData({
  592. name: vm.name,
  593. value: vm.modelValue,
  594. });
  595. }, {
  596. immediate: true,
  597. });
  598. }
  599. }
  600. function initData(_) {
  601. return {};
  602. }
  603. function initPropsObserver(componentOptions) {
  604. const observe = function observe() {
  605. const up = this.properties.uP;
  606. if (!up) {
  607. return;
  608. }
  609. if (this.$vm) {
  610. updateComponentProps(up, this.$vm.$);
  611. }
  612. else if (this.properties.uT === 'm') {
  613. // 小程序组件
  614. updateMiniProgramComponentProperties(up, this);
  615. }
  616. };
  617. {
  618. componentOptions.properties.uP.observer = observe;
  619. }
  620. }
  621. function updateMiniProgramComponentProperties(up, mpInstance) {
  622. const prevProps = mpInstance.properties;
  623. const nextProps = findComponentPropsData(up) || {};
  624. if (hasPropsChanged(prevProps, nextProps, false)) {
  625. mpInstance.setData(nextProps);
  626. }
  627. }
  628. function updateComponentProps(up, instance) {
  629. const prevProps = toRaw(instance.props);
  630. const nextProps = findComponentPropsData(up) || {};
  631. if (hasPropsChanged(prevProps, nextProps)) {
  632. updateProps(instance, nextProps, prevProps, false);
  633. if (hasQueueJob(instance.update)) {
  634. invalidateJob(instance.update);
  635. }
  636. {
  637. // 字节跳动小程序 https://github.com/dcloudio/uni-app/issues/3340
  638. // 百度小程序 https://github.com/dcloudio/uni-app/issues/3612
  639. if (!hasQueueJob(instance.update)) {
  640. instance.update();
  641. }
  642. }
  643. }
  644. }
  645. function hasPropsChanged(prevProps, nextProps, checkLen = true) {
  646. const nextKeys = Object.keys(nextProps);
  647. if (checkLen && nextKeys.length !== Object.keys(prevProps).length) {
  648. return true;
  649. }
  650. for (let i = 0; i < nextKeys.length; i++) {
  651. const key = nextKeys[i];
  652. if (nextProps[key] !== prevProps[key]) {
  653. return true;
  654. }
  655. }
  656. return false;
  657. }
  658. function initBehaviors(vueOptions) {
  659. const vueBehaviors = vueOptions.behaviors;
  660. let vueProps = vueOptions.props;
  661. if (!vueProps) {
  662. vueOptions.props = vueProps = [];
  663. }
  664. const behaviors = [];
  665. if (isArray(vueBehaviors)) {
  666. vueBehaviors.forEach((behavior) => {
  667. behaviors.push(behavior.replace('uni://', 'swan://'));
  668. if (behavior === 'uni://form-field') {
  669. if (isArray(vueProps)) {
  670. vueProps.push('name');
  671. vueProps.push('modelValue');
  672. }
  673. else {
  674. vueProps.name = {
  675. type: String,
  676. default: '',
  677. };
  678. vueProps.modelValue = {
  679. type: [String, Number, Boolean, Array, Object, Date],
  680. default: '',
  681. };
  682. }
  683. }
  684. });
  685. }
  686. return behaviors;
  687. }
  688. function applyOptions(componentOptions, vueOptions) {
  689. componentOptions.data = initData();
  690. componentOptions.behaviors = initBehaviors(vueOptions);
  691. }
  692. function parseComponent(vueOptions, { parse, mocks, isPage, initRelation, handleLink, initLifetimes, }) {
  693. vueOptions = vueOptions.default || vueOptions;
  694. const options = {
  695. multipleSlots: true,
  696. // styleIsolation: 'apply-shared',
  697. addGlobalClass: true,
  698. pureDataPattern: /^uP$/,
  699. };
  700. if (isArray(vueOptions.mixins)) {
  701. vueOptions.mixins.forEach((item) => {
  702. if (isObject(item.options)) {
  703. extend(options, item.options);
  704. }
  705. });
  706. }
  707. if (vueOptions.options) {
  708. extend(options, vueOptions.options);
  709. }
  710. const mpComponentOptions = {
  711. options,
  712. lifetimes: initLifetimes({ mocks, isPage, initRelation, vueOptions }),
  713. pageLifetimes: {
  714. show() {
  715. if (__VUE_PROD_DEVTOOLS__) {
  716. devtoolsComponentAdded(this.$vm.$);
  717. }
  718. this.$vm && this.$vm.$callHook('onPageShow');
  719. },
  720. hide() {
  721. this.$vm && this.$vm.$callHook('onPageHide');
  722. },
  723. resize(size) {
  724. this.$vm && this.$vm.$callHook('onPageResize', size);
  725. },
  726. },
  727. methods: {
  728. __l: handleLink,
  729. },
  730. };
  731. if (__VUE_OPTIONS_API__) {
  732. applyOptions(mpComponentOptions, vueOptions);
  733. }
  734. initProps(mpComponentOptions);
  735. initPropsObserver(mpComponentOptions);
  736. initExtraOptions(mpComponentOptions, vueOptions);
  737. initWxsCallMethods(mpComponentOptions.methods, vueOptions.wxsCallMethods);
  738. if (parse) {
  739. parse(mpComponentOptions, { handleLink });
  740. }
  741. return mpComponentOptions;
  742. }
  743. function initCreateComponent(parseOptions) {
  744. return function createComponent(vueComponentOptions) {
  745. return Component(parseComponent(vueComponentOptions, parseOptions));
  746. };
  747. }
  748. let $createComponentFn;
  749. let $destroyComponentFn;
  750. function getAppVm() {
  751. if (process.env.UNI_MP_PLUGIN) {
  752. return swan.$vm;
  753. }
  754. if (process.env.UNI_SUBPACKAGE) {
  755. return swan.$subpackages[process.env.UNI_SUBPACKAGE].$vm;
  756. }
  757. return getApp().$vm;
  758. }
  759. function $createComponent(initialVNode, options) {
  760. if (!$createComponentFn) {
  761. $createComponentFn = getAppVm().$createComponent;
  762. }
  763. const proxy = $createComponentFn(initialVNode, options);
  764. return getExposeProxy(proxy.$) || proxy;
  765. }
  766. function $destroyComponent(instance) {
  767. if (!$destroyComponentFn) {
  768. $destroyComponentFn = getAppVm().$destroyComponent;
  769. }
  770. return $destroyComponentFn(instance);
  771. }
  772. function parsePage(vueOptions, parseOptions) {
  773. const { parse, mocks, isPage, initRelation, handleLink, initLifetimes } = parseOptions;
  774. const miniProgramPageOptions = parseComponent(vueOptions, {
  775. mocks,
  776. isPage,
  777. initRelation,
  778. handleLink,
  779. initLifetimes,
  780. });
  781. initPageProps(miniProgramPageOptions, (vueOptions.default || vueOptions).props);
  782. const methods = miniProgramPageOptions.methods;
  783. methods.onLoad = function (query) {
  784. this.options = query;
  785. this.$page = {
  786. fullPath: addLeadingSlash(this.route + stringifyQuery(query)),
  787. };
  788. return this.$vm && this.$vm.$callHook(ON_LOAD, query);
  789. };
  790. initHooks(methods, PAGE_INIT_HOOKS);
  791. {
  792. initUnknownHooks(methods, vueOptions, [ON_INIT, ON_READY]);
  793. }
  794. initRuntimeHooks(methods, vueOptions.__runtimeHooks);
  795. initMixinRuntimeHooks(methods);
  796. parse && parse(miniProgramPageOptions, { handleLink });
  797. return miniProgramPageOptions;
  798. }
  799. function initCreatePage(parseOptions) {
  800. return function createPage(vuePageOptions) {
  801. return Component(parsePage(vuePageOptions, parseOptions));
  802. };
  803. }
  804. /**
  805. * 用于延迟调用 setData
  806. * 在 setData 真实调用的时机需执行 fixSetDataEnd
  807. * @param {*} mpInstance
  808. */
  809. function fixSetDataStart(mpInstance) {
  810. const setData = mpInstance.setData;
  811. const setDataArgs = [];
  812. mpInstance.setData = function () {
  813. setDataArgs.push(arguments);
  814. };
  815. mpInstance.__fixInitData = function () {
  816. this.setData = setData;
  817. const fn = () => {
  818. setDataArgs.forEach((args) => {
  819. setData.apply(this, args);
  820. });
  821. };
  822. if (setDataArgs.length) {
  823. if (this.groupSetData) {
  824. this.groupSetData(fn);
  825. }
  826. else {
  827. fn();
  828. }
  829. }
  830. };
  831. }
  832. /**
  833. * 恢复真实的 setData 方法
  834. * @param {*} mpInstance
  835. */
  836. function fixSetDataEnd(mpInstance) {
  837. if (mpInstance.__fixInitData) {
  838. mpInstance.__fixInitData();
  839. delete mpInstance.__fixInitData;
  840. }
  841. }
  842. const MPPage = Page;
  843. const MPComponent = Component;
  844. function initTriggerEvent(mpInstance) {
  845. const oldTriggerEvent = mpInstance.triggerEvent;
  846. const newTriggerEvent = function (event, ...args) {
  847. return oldTriggerEvent.apply(mpInstance, [customizeEvent(event), ...args]);
  848. };
  849. // 京东小程序triggerEvent为只读属性
  850. try {
  851. mpInstance.triggerEvent = newTriggerEvent;
  852. }
  853. catch (error) {
  854. mpInstance._triggerEvent = newTriggerEvent;
  855. }
  856. }
  857. function initMiniProgramHook(name, options, isComponent) {
  858. const oldHook = options[name];
  859. if (!oldHook) {
  860. options[name] = function () {
  861. initTriggerEvent(this);
  862. };
  863. }
  864. else {
  865. options[name] = function (...args) {
  866. initTriggerEvent(this);
  867. return oldHook.apply(this, args);
  868. };
  869. }
  870. }
  871. Page = function (options) {
  872. initMiniProgramHook(ON_LOAD, options);
  873. return MPPage(options);
  874. };
  875. {
  876. Page.after = MPPage.after;
  877. }
  878. Component = function (options) {
  879. initMiniProgramHook('created', options);
  880. // 小程序组件
  881. const isVueComponent = options.properties && options.properties.uP;
  882. if (!isVueComponent) {
  883. initProps(options);
  884. initPropsObserver(options);
  885. }
  886. return MPComponent(options);
  887. };
  888. function parse$2(appOptions) {
  889. // 百度 onShow 竟然会在 onLaunch 之前
  890. appOptions.onShow = function onShow(args) {
  891. if (!this.$vm) {
  892. this.onLaunch(args);
  893. }
  894. this.$vm.$callHook(ON_SHOW, args);
  895. };
  896. }
  897. var parseAppOptions = /*#__PURE__*/Object.freeze({
  898. __proto__: null,
  899. parse: parse$2
  900. });
  901. // @ts-ignore
  902. function initLifetimes({ mocks, isPage, initRelation, vueOptions, }) {
  903. return {
  904. attached() {
  905. // 微信 和 QQ 不需要延迟 setRef
  906. {
  907. initSetRef(this);
  908. }
  909. let properties = this.properties;
  910. initVueIds(properties.uI, this);
  911. const relationOptions = {
  912. vuePid: this._$vuePid,
  913. };
  914. // 处理父子关系
  915. initRelation(this, relationOptions);
  916. // 初始化 vue 实例
  917. const mpInstance = this;
  918. const isMiniProgramPage = isPage(mpInstance);
  919. let propsData = properties;
  920. if (isMiniProgramPage) {
  921. {
  922. propsData = this.pageinstance._$props;
  923. delete this.pageinstance._$props;
  924. }
  925. }
  926. this.$vm = $createComponent({
  927. type: vueOptions,
  928. props: findPropsData(propsData, isMiniProgramPage),
  929. }, {
  930. mpType: isMiniProgramPage ? 'page' : 'component',
  931. mpInstance,
  932. slots: properties.uS || {},
  933. parentComponent: relationOptions.parent && relationOptions.parent.$,
  934. onBeforeSetup(instance, options) {
  935. initRefs(instance, mpInstance);
  936. initMocks(instance, mpInstance, mocks);
  937. initComponentInstance(instance, options);
  938. },
  939. });
  940. if (!isMiniProgramPage) {
  941. initFormField(this.$vm);
  942. }
  943. },
  944. ready() {
  945. // 当组件 props 默认值为 true,初始化时传入 false 会导致 created,ready 触发, 但 attached 不触发
  946. // https://developers.weixin.qq.com/community/develop/doc/00066ae2844cc0f8eb883e2a557800
  947. if (this.$vm) {
  948. {
  949. nextSetDataTick(this, () => {
  950. this.$vm.$callHook('mounted');
  951. this.$vm.$callHook(ON_READY);
  952. });
  953. }
  954. }
  955. },
  956. detached() {
  957. if (this.$vm) {
  958. pruneComponentPropsCache(this.$vm.$.uid);
  959. $destroyComponent(this.$vm);
  960. }
  961. },
  962. };
  963. }
  964. function handleLink(event) {
  965. // detail 是微信,value 是百度(dipatch)
  966. const detail = (event.detail ||
  967. event.value);
  968. const vuePid = detail.vuePid;
  969. let parentVm;
  970. if (vuePid) {
  971. parentVm = findVmByVueId(this.$vm, vuePid);
  972. }
  973. if (!parentVm) {
  974. parentVm = this.$vm;
  975. }
  976. detail.parent = parentVm;
  977. }
  978. const mocks = ['nodeId', 'componentName', '_componentId', 'uniquePrefix'];
  979. function isPage(mpInstance) {
  980. return !!mpInstance.methods.onLoad;
  981. }
  982. function initRelation(mpInstance, detail) {
  983. mpInstance.dispatch('__l', detail);
  984. }
  985. const newLifecycle = /*#__PURE__*/ swan.canIUse('lifecycle-2-0');
  986. function parse$1(componentOptions) {
  987. const methods = componentOptions.methods;
  988. const lifetimes = componentOptions.lifetimes;
  989. // 关于百度小程序生命周期的说明(组件作为页面时):
  990. // lifetimes:attached --> methods:onShow --> methods:onLoad --> methods:onReady
  991. // 这里在强制将onShow挪到onLoad之后触发,另外一处修改在page-parser.js
  992. const oldAttached = lifetimes.attached;
  993. // 百度小程序基础库 3.260 以上支持页面 onInit 生命周期,提前创建 vm 实例
  994. lifetimes.onInit = function onInit(query) {
  995. // 百度小程序后续可能移除 pageinstance 属性,为向后兼容进行补充
  996. if (!this.pageinstance || !this.pageinstance.setData) {
  997. const pages = getCurrentPages();
  998. this.pageinstance = pages[pages.length - 1];
  999. }
  1000. this.pageinstance._$props = query;
  1001. // 处理百度小程序 onInit 生命周期调用 setData 无效的问题
  1002. fixSetDataStart(this);
  1003. oldAttached.call(this);
  1004. this.pageinstance.$vm = this.$vm;
  1005. this.$vm.$callHook(ON_INIT, query);
  1006. };
  1007. lifetimes.attached = function attached() {
  1008. if (!this.$vm) {
  1009. oldAttached.call(this);
  1010. }
  1011. else {
  1012. initMocks(this.$vm.$, this, mocks);
  1013. fixSetDataEnd(this);
  1014. }
  1015. if (isPage(this) && this.$vm) {
  1016. // 百度 onLoad 在 attached 之前触发(基础库小于 3.70)
  1017. // 百度 当组件作为页面时 pageinstance 不是原来组件的 instance
  1018. const pageInstance = this.pageinstance;
  1019. pageInstance.$vm = this.$vm;
  1020. if (hasOwn(pageInstance, '_$args')) {
  1021. this.$vm.$callHook(ON_LOAD, pageInstance._$args);
  1022. this.$vm.$callHook(ON_SHOW);
  1023. delete pageInstance._$args;
  1024. }
  1025. }
  1026. else {
  1027. // 百度小程序组件不触发 methods 内的 onReady
  1028. if (this.$vm) {
  1029. nextSetDataTick(this, () => {
  1030. this.$vm.$callHook('mounted');
  1031. });
  1032. }
  1033. }
  1034. };
  1035. if (newLifecycle) {
  1036. methods.onReady = lifetimes.ready;
  1037. delete lifetimes.ready;
  1038. }
  1039. componentOptions.messages = {
  1040. __l: methods.__l,
  1041. };
  1042. delete methods.__l;
  1043. // 百度小程序自定义组件,不支持绑定动态事件,故由 __e 分发
  1044. methods.__e = handleEvent;
  1045. }
  1046. var parseComponentOptions = /*#__PURE__*/Object.freeze({
  1047. __proto__: null,
  1048. handleLink: handleLink,
  1049. initLifetimes: initLifetimes,
  1050. initRelation: initRelation,
  1051. isPage: isPage,
  1052. mocks: mocks,
  1053. parse: parse$1
  1054. });
  1055. function parse(pageOptions) {
  1056. parse$1(pageOptions);
  1057. const methods = pageOptions.methods;
  1058. // 纠正百度小程序生命周期methods:onShow在methods:onLoad之前触发的问题
  1059. methods.onShow = function onShow() {
  1060. if (this.$vm && this._$loaded) {
  1061. this.$vm.$callHook(ON_SHOW);
  1062. }
  1063. };
  1064. methods.onLoad = function onLoad(query) {
  1065. // 百度 onLoad 在 attached 之前触发,先存储 args, 在 attached 里边触发 onLoad
  1066. if (this.$vm) {
  1067. this._$loaded = true;
  1068. const copyQuery = extend({}, query);
  1069. delete copyQuery.__id__;
  1070. this.options = copyQuery;
  1071. this.pageinstance.$page = this.$page = {
  1072. fullPath: '/' + this.pageinstance.route + stringifyQuery(copyQuery),
  1073. };
  1074. this.$vm.$callHook(ON_LOAD, query);
  1075. this.$vm.$callHook(ON_SHOW);
  1076. }
  1077. else {
  1078. this.pageinstance._$args = query;
  1079. }
  1080. };
  1081. }
  1082. var parsePageOptions = /*#__PURE__*/Object.freeze({
  1083. __proto__: null,
  1084. handleLink: handleLink,
  1085. initLifetimes: initLifetimes,
  1086. initRelation: initRelation,
  1087. isPage: isPage,
  1088. mocks: mocks,
  1089. parse: parse
  1090. });
  1091. const createApp = initCreateApp(parseAppOptions);
  1092. const createPage = initCreatePage(parsePageOptions);
  1093. const createComponent = initCreateComponent(parseComponentOptions);
  1094. const createSubpackageApp = initCreateSubpackageApp(parseAppOptions);
  1095. swan.EventChannel = EventChannel;
  1096. swan.createApp = global.createApp = createApp;
  1097. swan.createPage = createPage;
  1098. swan.createComponent = createComponent;
  1099. swan.createSubpackageApp = global.createSubpackageApp =
  1100. createSubpackageApp;
  1101. export { createApp, createComponent, createPage, createSubpackageApp };