uni.mp.esm.js 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094
  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, customizeEvent } from '@dcloudio/uni-shared';
  2. import { isArray, isFunction, hasOwn, extend, isPlainObject, isObject } from '@vue/shared';
  3. import { devtoolsComponentRemoved, devtoolsComponentAdded, ref, nextTick, findComponentPropsData, toRaw, updateProps, hasQueueJob, invalidateJob, getExposeProxy, isRef, 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. scope.triggerEvent(event, detail);
  18. }
  19. }
  20. return oldEmit.apply(this, [event, ...args]);
  21. };
  22. }
  23. function initBaseInstance(instance, options) {
  24. const ctx = instance.ctx;
  25. // mp
  26. ctx.mpType = options.mpType; // @deprecated
  27. ctx.$mpType = options.mpType;
  28. ctx.$mpPlatform = "mp-lark";
  29. ctx.$scope = options.mpInstance;
  30. // TODO @deprecated
  31. ctx.$mp = {};
  32. if (__VUE_OPTIONS_API__) {
  33. ctx._self = {};
  34. }
  35. // slots
  36. instance.slots = {};
  37. if (isArray(options.slots) && options.slots.length) {
  38. options.slots.forEach((name) => {
  39. instance.slots[name] = true;
  40. });
  41. if (instance.slots[SLOT_DEFAULT_NAME]) {
  42. instance.slots.default = true;
  43. }
  44. }
  45. ctx.getOpenerEventChannel = function () {
  46. if (!this.__eventChannel__) {
  47. this.__eventChannel__ = new EventChannel();
  48. }
  49. return this.__eventChannel__;
  50. };
  51. ctx.$hasHook = hasHook;
  52. ctx.$callHook = callHook;
  53. // $emit
  54. instance.emit = createEmitFn(instance.emit, ctx);
  55. }
  56. function initComponentInstance(instance, options) {
  57. initBaseInstance(instance, options);
  58. const ctx = instance.ctx;
  59. MP_METHODS.forEach((method) => {
  60. ctx[method] = function (...args) {
  61. const mpInstance = ctx.$scope;
  62. if (mpInstance && mpInstance[method]) {
  63. return mpInstance[method].apply(mpInstance, args);
  64. }
  65. };
  66. });
  67. }
  68. function initMocks(instance, mpInstance, mocks) {
  69. const ctx = instance.ctx;
  70. mocks.forEach((mock) => {
  71. if (hasOwn(mpInstance, mock)) {
  72. instance[mock] = ctx[mock] = mpInstance[mock];
  73. }
  74. });
  75. }
  76. function hasHook(name) {
  77. const hooks = this.$[name];
  78. if (hooks && hooks.length) {
  79. return true;
  80. }
  81. return false;
  82. }
  83. function callHook(name, args) {
  84. if (name === 'mounted') {
  85. callHook.call(this, 'bm'); // beforeMount
  86. this.$.isMounted = true;
  87. name = 'm';
  88. }
  89. {
  90. if (name === 'onLoad' &&
  91. args &&
  92. args.__id__ &&
  93. isFunction(tt.getEventChannel)) {
  94. this.__eventChannel__ = tt.getEventChannel(args.__id__);
  95. delete args.__id__;
  96. }
  97. }
  98. // 处理飞书小程序页面切换uni-vue-devtools无法更新数据问题
  99. if (__VUE_PROD_DEVTOOLS__ &&
  100. name === 'onShow') {
  101. devtoolsComponentRemoved(this.$);
  102. devtoolsComponentAdded(this.$);
  103. }
  104. const hooks = this.$[name];
  105. return hooks && invokeArrayFns(hooks, args);
  106. }
  107. const PAGE_INIT_HOOKS = [
  108. ON_LOAD,
  109. ON_SHOW,
  110. ON_HIDE,
  111. ON_UNLOAD,
  112. ON_RESIZE,
  113. ON_TAB_ITEM_TAP,
  114. ON_REACH_BOTTOM,
  115. ON_PULL_DOWN_REFRESH,
  116. ON_ADD_TO_FAVORITES,
  117. // 'onReady', // lifetimes.ready
  118. // 'onPageScroll', // 影响性能,开发者手动注册
  119. // 'onShareTimeline', // 右上角菜单,开发者手动注册
  120. // 'onShareAppMessage' // 右上角菜单,开发者手动注册
  121. ];
  122. function findHooks(vueOptions, hooks = new Set()) {
  123. if (vueOptions) {
  124. Object.keys(vueOptions).forEach((name) => {
  125. if (isUniLifecycleHook(name, vueOptions[name])) {
  126. hooks.add(name);
  127. }
  128. });
  129. if (__VUE_OPTIONS_API__) {
  130. const { extends: extendsOptions, mixins } = vueOptions;
  131. if (mixins) {
  132. mixins.forEach((mixin) => findHooks(mixin, hooks));
  133. }
  134. if (extendsOptions) {
  135. findHooks(extendsOptions, hooks);
  136. }
  137. }
  138. }
  139. return hooks;
  140. }
  141. function initHook(mpOptions, hook, excludes) {
  142. if (excludes.indexOf(hook) === -1 && !hasOwn(mpOptions, hook)) {
  143. mpOptions[hook] = function (args) {
  144. if (hook === 'onError') {
  145. return getApp().$vm.$callHook(hook, args);
  146. }
  147. return this.$vm && this.$vm.$callHook(hook, args);
  148. };
  149. }
  150. }
  151. const EXCLUDE_HOOKS = [ON_READY];
  152. function initHooks(mpOptions, hooks, excludes = EXCLUDE_HOOKS) {
  153. hooks.forEach((hook) => initHook(mpOptions, hook, excludes));
  154. }
  155. function initUnknownHooks(mpOptions, vueOptions, excludes = EXCLUDE_HOOKS) {
  156. findHooks(vueOptions).forEach((hook) => initHook(mpOptions, hook, excludes));
  157. }
  158. function initRuntimeHooks(mpOptions, runtimeHooks) {
  159. if (!runtimeHooks) {
  160. return;
  161. }
  162. const hooks = Object.keys(MINI_PROGRAM_PAGE_RUNTIME_HOOKS);
  163. hooks.forEach((hook) => {
  164. if (runtimeHooks & MINI_PROGRAM_PAGE_RUNTIME_HOOKS[hook]) {
  165. initHook(mpOptions, hook, []);
  166. }
  167. });
  168. }
  169. const findMixinRuntimeHooks = /*#__PURE__*/ once(() => {
  170. const runtimeHooks = [];
  171. const app = isFunction(getApp) && getApp({ allowDefault: true });
  172. if (app && app.$vm && app.$vm.$) {
  173. const mixins = app.$vm.$.appContext.mixins;
  174. if (isArray(mixins)) {
  175. const hooks = Object.keys(MINI_PROGRAM_PAGE_RUNTIME_HOOKS);
  176. mixins.forEach((mixin) => {
  177. hooks.forEach((hook) => {
  178. if (hasOwn(mixin, hook) && !runtimeHooks.includes(hook)) {
  179. runtimeHooks.push(hook);
  180. }
  181. });
  182. });
  183. }
  184. }
  185. return runtimeHooks;
  186. });
  187. function initMixinRuntimeHooks(mpOptions) {
  188. initHooks(mpOptions, findMixinRuntimeHooks());
  189. }
  190. const HOOKS = [
  191. ON_SHOW,
  192. ON_HIDE,
  193. ON_ERROR,
  194. ON_THEME_CHANGE,
  195. ON_PAGE_NOT_FOUND,
  196. ON_UNHANDLE_REJECTION,
  197. ];
  198. function parseApp(instance, parseAppOptions) {
  199. const internalInstance = instance.$;
  200. if (__VUE_PROD_DEVTOOLS__) {
  201. // 定制 App 的 $children
  202. Object.defineProperty(internalInstance.ctx, '$children', {
  203. get() {
  204. return getCurrentPages().map((page) => page.$vm);
  205. },
  206. });
  207. }
  208. const appOptions = {
  209. globalData: (instance.$options && instance.$options.globalData) || {},
  210. $vm: instance,
  211. onLaunch(options) {
  212. this.$vm = instance; // 飞书小程序可能会把 AppOptions 序列化,导致 $vm 对象部分属性丢失
  213. const ctx = internalInstance.ctx;
  214. if (this.$vm && ctx.$scope) {
  215. // 已经初始化过了,主要是为了百度,百度 onShow 在 onLaunch 之前
  216. return;
  217. }
  218. initBaseInstance(internalInstance, {
  219. mpType: 'app',
  220. mpInstance: this,
  221. slots: [],
  222. });
  223. ctx.globalData = this.globalData;
  224. instance.$callHook(ON_LAUNCH, options);
  225. },
  226. };
  227. const { onError } = internalInstance;
  228. if (onError) {
  229. internalInstance.appContext.config.errorHandler = (err) => {
  230. instance.$callHook(ON_ERROR, err);
  231. };
  232. }
  233. initLocale(instance);
  234. const vueOptions = instance.$.type;
  235. initHooks(appOptions, HOOKS);
  236. initUnknownHooks(appOptions, vueOptions);
  237. if (__VUE_OPTIONS_API__) {
  238. const methods = vueOptions.methods;
  239. methods && extend(appOptions, methods);
  240. }
  241. if (parseAppOptions) {
  242. parseAppOptions.parse(appOptions);
  243. }
  244. return appOptions;
  245. }
  246. function initCreateApp(parseAppOptions) {
  247. return function createApp(vm) {
  248. return App(parseApp(vm, parseAppOptions));
  249. };
  250. }
  251. function initCreateSubpackageApp(parseAppOptions) {
  252. return function createApp(vm) {
  253. const appOptions = parseApp(vm, parseAppOptions);
  254. const app = isFunction(getApp) &&
  255. getApp({
  256. allowDefault: true,
  257. });
  258. if (!app)
  259. return;
  260. vm.$.ctx.$scope = app;
  261. const globalData = app.globalData;
  262. if (globalData) {
  263. Object.keys(appOptions.globalData).forEach((name) => {
  264. if (!hasOwn(globalData, name)) {
  265. globalData[name] = appOptions.globalData[name];
  266. }
  267. });
  268. }
  269. Object.keys(appOptions).forEach((name) => {
  270. if (!hasOwn(app, name)) {
  271. app[name] = appOptions[name];
  272. }
  273. });
  274. initAppLifecycle(appOptions, vm);
  275. if (process.env.UNI_SUBPACKAGE) {
  276. (tt.$subpackages || (tt.$subpackages = {}))[process.env.UNI_SUBPACKAGE] = {
  277. $vm: vm,
  278. };
  279. }
  280. };
  281. }
  282. function initAppLifecycle(appOptions, vm) {
  283. if (isFunction(appOptions.onLaunch)) {
  284. const args = tt.getLaunchOptionsSync && tt.getLaunchOptionsSync();
  285. appOptions.onLaunch(args);
  286. }
  287. if (isFunction(appOptions.onShow) && tt.onAppShow) {
  288. tt.onAppShow((args) => {
  289. vm.$callHook('onShow', args);
  290. });
  291. }
  292. if (isFunction(appOptions.onHide) && tt.onAppHide) {
  293. tt.onAppHide((args) => {
  294. vm.$callHook('onHide', args);
  295. });
  296. }
  297. }
  298. function initLocale(appVm) {
  299. const locale = ref(normalizeLocale(tt.getSystemInfoSync().language) || LOCALE_EN);
  300. Object.defineProperty(appVm, '$locale', {
  301. get() {
  302. return locale.value;
  303. },
  304. set(v) {
  305. locale.value = v;
  306. },
  307. });
  308. }
  309. function initVueIds(vueIds, mpInstance) {
  310. if (!vueIds) {
  311. return;
  312. }
  313. const ids = vueIds.split(',');
  314. const len = ids.length;
  315. if (len === 1) {
  316. mpInstance._$vueId = ids[0];
  317. }
  318. else if (len === 2) {
  319. mpInstance._$vueId = ids[0];
  320. mpInstance._$vuePid = ids[1];
  321. }
  322. }
  323. const EXTRAS = ['externalClasses'];
  324. function initExtraOptions(miniProgramComponentOptions, vueOptions) {
  325. EXTRAS.forEach((name) => {
  326. if (hasOwn(vueOptions, name)) {
  327. miniProgramComponentOptions[name] = vueOptions[name];
  328. }
  329. });
  330. }
  331. function initWxsCallMethods(methods, wxsCallMethods) {
  332. if (!isArray(wxsCallMethods)) {
  333. return;
  334. }
  335. wxsCallMethods.forEach((callMethod) => {
  336. methods[callMethod] = function (args) {
  337. return this.$vm[callMethod](args);
  338. };
  339. });
  340. }
  341. function selectAllComponents(mpInstance, selector, $refs) {
  342. const components = mpInstance.selectAllComponents(selector);
  343. components.forEach((component) => {
  344. const ref = component.properties.uR;
  345. $refs[ref] = component.$vm || component;
  346. });
  347. }
  348. function initRefs(instance, mpInstance) {
  349. Object.defineProperty(instance, 'refs', {
  350. get() {
  351. const $refs = {};
  352. selectAllComponents(mpInstance, '.r', $refs);
  353. const forComponents = mpInstance.selectAllComponents('.r-i-f');
  354. forComponents.forEach((component) => {
  355. const ref = component.properties.uR;
  356. if (!ref) {
  357. return;
  358. }
  359. if (!$refs[ref]) {
  360. $refs[ref] = [];
  361. }
  362. $refs[ref].push(component.$vm || component);
  363. });
  364. return $refs;
  365. },
  366. });
  367. }
  368. function findVmByVueId(instance, vuePid) {
  369. // 标准 vue3 中 没有 $children,定制了内核
  370. const $children = instance.$children;
  371. // 优先查找直属(反向查找:https://github.com/dcloudio/uni-app/issues/1200)
  372. for (let i = $children.length - 1; i >= 0; i--) {
  373. const childVm = $children[i];
  374. if (childVm.$scope._$vueId === vuePid) {
  375. return childVm;
  376. }
  377. }
  378. // 反向递归查找
  379. let parentVm;
  380. for (let i = $children.length - 1; i >= 0; i--) {
  381. parentVm = findVmByVueId($children[i], vuePid);
  382. if (parentVm) {
  383. return parentVm;
  384. }
  385. }
  386. }
  387. function nextSetDataTick(mpInstance, fn) {
  388. // 随便设置一个字段来触发回调(部分平台必须有字段才可以,比如头条)
  389. mpInstance.setData({ r1: 1 }, () => fn());
  390. }
  391. function initSetRef(mpInstance) {
  392. if (!mpInstance._$setRef) {
  393. mpInstance._$setRef = (fn) => {
  394. nextTick(() => nextSetDataTick(mpInstance, fn));
  395. };
  396. }
  397. }
  398. const builtInProps = [
  399. // 百度小程序,快手小程序自定义组件不支持绑定动态事件,动态dataset,故通过props传递事件信息
  400. // event-opts
  401. 'eO',
  402. // 组件 ref
  403. 'uR',
  404. // 组件 ref-in-for
  405. 'uRIF',
  406. // 组件 id
  407. 'uI',
  408. // 组件类型 m: 小程序组件
  409. 'uT',
  410. // 组件 props
  411. 'uP',
  412. // 小程序不能直接定义 $slots 的 props,所以通过 vueSlots 转换到 $slots
  413. 'uS',
  414. ];
  415. function initDefaultProps(options, isBehavior = false) {
  416. const properties = {};
  417. if (!isBehavior) {
  418. // 均不指定类型,避免微信小程序 property received type-uncompatible value 警告
  419. builtInProps.forEach((name) => {
  420. properties[name] = {
  421. type: null,
  422. value: '',
  423. };
  424. });
  425. // 小程序不能直接定义 $slots 的 props,所以通过 vueSlots 转换到 $slots
  426. properties.uS = {
  427. type: null,
  428. value: [],
  429. observer: function (newVal) {
  430. const $slots = Object.create(null);
  431. newVal &&
  432. newVal.forEach((slotName) => {
  433. $slots[slotName] = true;
  434. });
  435. this.setData({
  436. $slots,
  437. });
  438. },
  439. };
  440. }
  441. if (options.behaviors) {
  442. // wx://form-field
  443. if (options.behaviors.includes('tt://form-field')) {
  444. if (!options.properties || !options.properties.name) {
  445. properties.name = {
  446. type: null,
  447. value: '',
  448. };
  449. }
  450. if (!options.properties || !options.properties.value) {
  451. properties.value = {
  452. type: null,
  453. value: '',
  454. };
  455. }
  456. }
  457. }
  458. return properties;
  459. }
  460. function initVirtualHostProps(options) {
  461. const properties = {};
  462. return properties;
  463. }
  464. /**
  465. *
  466. * @param mpComponentOptions
  467. * @param isBehavior
  468. */
  469. function initProps(mpComponentOptions) {
  470. if (!mpComponentOptions.properties) {
  471. mpComponentOptions.properties = {};
  472. }
  473. extend(mpComponentOptions.properties, initDefaultProps(mpComponentOptions), initVirtualHostProps(mpComponentOptions.options));
  474. }
  475. const PROP_TYPES = [String, Number, Boolean, Object, Array, null];
  476. function parsePropType(type, defaultValue) {
  477. // [String]=>String
  478. if (isArray(type) && type.length === 1) {
  479. return type[0];
  480. }
  481. return type;
  482. }
  483. function normalizePropType(type, defaultValue) {
  484. const res = parsePropType(type);
  485. return PROP_TYPES.indexOf(res) !== -1 ? res : null;
  486. }
  487. /**
  488. * 初始化页面 props,方便接收页面参数,类型均为String,默认值均为''
  489. * @param param
  490. * @param rawProps
  491. */
  492. function initPageProps({ properties }, rawProps) {
  493. if (isArray(rawProps)) {
  494. rawProps.forEach((key) => {
  495. properties[key] = {
  496. type: String,
  497. value: '',
  498. };
  499. });
  500. }
  501. else if (isPlainObject(rawProps)) {
  502. Object.keys(rawProps).forEach((key) => {
  503. const opts = rawProps[key];
  504. if (isPlainObject(opts)) {
  505. // title:{type:String,default:''}
  506. let value = opts.default;
  507. if (isFunction(value)) {
  508. value = value();
  509. }
  510. const type = opts.type;
  511. opts.type = normalizePropType(type);
  512. properties[key] = {
  513. type: opts.type,
  514. value,
  515. };
  516. }
  517. else {
  518. // content:String
  519. properties[key] = {
  520. type: normalizePropType(opts),
  521. };
  522. }
  523. });
  524. }
  525. }
  526. function findPropsData(properties, isPage) {
  527. return ((isPage
  528. ? findPagePropsData(properties)
  529. : findComponentPropsData(properties.uP)) || {});
  530. }
  531. function findPagePropsData(properties) {
  532. const propsData = {};
  533. if (isPlainObject(properties)) {
  534. Object.keys(properties).forEach((name) => {
  535. if (builtInProps.indexOf(name) === -1) {
  536. propsData[name] = properties[name];
  537. }
  538. });
  539. }
  540. return propsData;
  541. }
  542. function initFormField(vm) {
  543. // 同步 form-field 的 name,value 值
  544. const vueOptions = vm.$options;
  545. if (isArray(vueOptions.behaviors) &&
  546. vueOptions.behaviors.includes('uni://form-field')) {
  547. vm.$watch('modelValue', () => {
  548. vm.$scope &&
  549. vm.$scope.setData({
  550. name: vm.name,
  551. value: vm.modelValue,
  552. });
  553. }, {
  554. immediate: true,
  555. });
  556. }
  557. }
  558. function initData(_) {
  559. return {};
  560. }
  561. function initPropsObserver(componentOptions) {
  562. const observe = function observe() {
  563. const up = this.properties.uP;
  564. if (!up) {
  565. return;
  566. }
  567. if (this.$vm) {
  568. updateComponentProps(up, this.$vm.$);
  569. }
  570. else if (this.properties.uT === 'm') {
  571. // 小程序组件
  572. updateMiniProgramComponentProperties(up, this);
  573. }
  574. };
  575. {
  576. componentOptions.properties.uP.observer = observe;
  577. }
  578. }
  579. function updateMiniProgramComponentProperties(up, mpInstance) {
  580. const prevProps = mpInstance.properties;
  581. const nextProps = findComponentPropsData(up) || {};
  582. if (hasPropsChanged(prevProps, nextProps, false)) {
  583. mpInstance.setData(nextProps);
  584. }
  585. }
  586. function updateComponentProps(up, instance) {
  587. const prevProps = toRaw(instance.props);
  588. const nextProps = findComponentPropsData(up) || {};
  589. if (hasPropsChanged(prevProps, nextProps)) {
  590. updateProps(instance, nextProps, prevProps, false);
  591. if (hasQueueJob(instance.update)) {
  592. invalidateJob(instance.update);
  593. }
  594. {
  595. instance.update();
  596. }
  597. }
  598. }
  599. function hasPropsChanged(prevProps, nextProps, checkLen = true) {
  600. const nextKeys = Object.keys(nextProps);
  601. if (checkLen && nextKeys.length !== Object.keys(prevProps).length) {
  602. return true;
  603. }
  604. for (let i = 0; i < nextKeys.length; i++) {
  605. const key = nextKeys[i];
  606. if (nextProps[key] !== prevProps[key]) {
  607. return true;
  608. }
  609. }
  610. return false;
  611. }
  612. function initBehaviors(vueOptions) {
  613. const vueBehaviors = vueOptions.behaviors;
  614. let vueProps = vueOptions.props;
  615. if (!vueProps) {
  616. vueOptions.props = vueProps = [];
  617. }
  618. const behaviors = [];
  619. if (isArray(vueBehaviors)) {
  620. vueBehaviors.forEach((behavior) => {
  621. behaviors.push(behavior.replace('uni://', 'tt://'));
  622. if (behavior === 'uni://form-field') {
  623. if (isArray(vueProps)) {
  624. vueProps.push('name');
  625. vueProps.push('modelValue');
  626. }
  627. else {
  628. vueProps.name = {
  629. type: String,
  630. default: '',
  631. };
  632. vueProps.modelValue = {
  633. type: [String, Number, Boolean, Array, Object, Date],
  634. default: '',
  635. };
  636. }
  637. }
  638. });
  639. }
  640. return behaviors;
  641. }
  642. function applyOptions(componentOptions, vueOptions) {
  643. componentOptions.data = initData();
  644. componentOptions.behaviors = initBehaviors(vueOptions);
  645. }
  646. function parseComponent(vueOptions, { parse, mocks, isPage, initRelation, handleLink, initLifetimes, }) {
  647. vueOptions = vueOptions.default || vueOptions;
  648. const options = {
  649. multipleSlots: true,
  650. // styleIsolation: 'apply-shared',
  651. addGlobalClass: true,
  652. pureDataPattern: /^uP$/,
  653. };
  654. if (isArray(vueOptions.mixins)) {
  655. vueOptions.mixins.forEach((item) => {
  656. if (isObject(item.options)) {
  657. extend(options, item.options);
  658. }
  659. });
  660. }
  661. if (vueOptions.options) {
  662. extend(options, vueOptions.options);
  663. }
  664. const mpComponentOptions = {
  665. options,
  666. lifetimes: initLifetimes({ mocks, isPage, initRelation, vueOptions }),
  667. pageLifetimes: {
  668. show() {
  669. if (__VUE_PROD_DEVTOOLS__) {
  670. devtoolsComponentAdded(this.$vm.$);
  671. }
  672. this.$vm && this.$vm.$callHook('onPageShow');
  673. },
  674. hide() {
  675. this.$vm && this.$vm.$callHook('onPageHide');
  676. },
  677. resize(size) {
  678. this.$vm && this.$vm.$callHook('onPageResize', size);
  679. },
  680. },
  681. methods: {
  682. __l: handleLink,
  683. },
  684. };
  685. if (__VUE_OPTIONS_API__) {
  686. applyOptions(mpComponentOptions, vueOptions);
  687. }
  688. initProps(mpComponentOptions);
  689. initPropsObserver(mpComponentOptions);
  690. initExtraOptions(mpComponentOptions, vueOptions);
  691. initWxsCallMethods(mpComponentOptions.methods, vueOptions.wxsCallMethods);
  692. if (parse) {
  693. parse(mpComponentOptions, { handleLink });
  694. }
  695. return mpComponentOptions;
  696. }
  697. function initCreateComponent(parseOptions) {
  698. return function createComponent(vueComponentOptions) {
  699. return Component(parseComponent(vueComponentOptions, parseOptions));
  700. };
  701. }
  702. let $createComponentFn;
  703. let $destroyComponentFn;
  704. function getAppVm() {
  705. if (process.env.UNI_MP_PLUGIN) {
  706. return tt.$vm;
  707. }
  708. if (process.env.UNI_SUBPACKAGE) {
  709. return tt.$subpackages[process.env.UNI_SUBPACKAGE].$vm;
  710. }
  711. return getApp().$vm;
  712. }
  713. function $createComponent(initialVNode, options) {
  714. if (!$createComponentFn) {
  715. $createComponentFn = getAppVm().$createComponent;
  716. }
  717. const proxy = $createComponentFn(initialVNode, options);
  718. return getExposeProxy(proxy.$) || proxy;
  719. }
  720. function $destroyComponent(instance) {
  721. if (!$destroyComponentFn) {
  722. $destroyComponentFn = getAppVm().$destroyComponent;
  723. }
  724. return $destroyComponentFn(instance);
  725. }
  726. function parsePage(vueOptions, parseOptions) {
  727. const { parse, mocks, isPage, initRelation, handleLink, initLifetimes } = parseOptions;
  728. const miniProgramPageOptions = parseComponent(vueOptions, {
  729. mocks,
  730. isPage,
  731. initRelation,
  732. handleLink,
  733. initLifetimes,
  734. });
  735. initPageProps(miniProgramPageOptions, (vueOptions.default || vueOptions).props);
  736. const methods = miniProgramPageOptions.methods;
  737. methods.onLoad = function (query) {
  738. this.options = query;
  739. this.$page = {
  740. fullPath: addLeadingSlash(this.route + stringifyQuery(query)),
  741. };
  742. return this.$vm && this.$vm.$callHook(ON_LOAD, query);
  743. };
  744. initHooks(methods, PAGE_INIT_HOOKS);
  745. {
  746. initUnknownHooks(methods, vueOptions);
  747. }
  748. initRuntimeHooks(methods, vueOptions.__runtimeHooks);
  749. initMixinRuntimeHooks(methods);
  750. parse && parse(miniProgramPageOptions, { handleLink });
  751. return miniProgramPageOptions;
  752. }
  753. function initCreatePage(parseOptions) {
  754. return function createPage(vuePageOptions) {
  755. return Component(parsePage(vuePageOptions, parseOptions));
  756. };
  757. }
  758. const MPPage = Page;
  759. const MPComponent = Component;
  760. function initTriggerEvent(mpInstance) {
  761. const oldTriggerEvent = mpInstance.triggerEvent;
  762. const newTriggerEvent = function (event, ...args) {
  763. return oldTriggerEvent.apply(mpInstance, [customizeEvent(event), ...args]);
  764. };
  765. // 京东小程序triggerEvent为只读属性
  766. try {
  767. mpInstance.triggerEvent = newTriggerEvent;
  768. }
  769. catch (error) {
  770. mpInstance._triggerEvent = newTriggerEvent;
  771. }
  772. }
  773. function initMiniProgramHook(name, options, isComponent) {
  774. if (isComponent) {
  775. // fix by Lxh 字节自定义组件Component构造器文档上写有created,但是实测只触发了lifetimes上的created
  776. options = options.lifetimes || {};
  777. }
  778. const oldHook = options[name];
  779. if (!oldHook) {
  780. options[name] = function () {
  781. initTriggerEvent(this);
  782. };
  783. }
  784. else {
  785. options[name] = function (...args) {
  786. initTriggerEvent(this);
  787. return oldHook.apply(this, args);
  788. };
  789. }
  790. }
  791. Page = function (options) {
  792. initMiniProgramHook(ON_LOAD, options);
  793. return MPPage(options);
  794. };
  795. Component = function (options) {
  796. initMiniProgramHook('created', options, true);
  797. // 小程序组件
  798. const isVueComponent = options.properties && options.properties.uP;
  799. if (!isVueComponent) {
  800. initProps(options);
  801. initPropsObserver(options);
  802. }
  803. return MPComponent(options);
  804. };
  805. function provide(instance, key, value) {
  806. if (!instance) {
  807. if ((process.env.NODE_ENV !== 'production')) {
  808. console.warn(`provide() can only be used inside setup().`);
  809. }
  810. }
  811. else {
  812. let provides = instance.provides;
  813. // by default an instance inherits its parent's provides object
  814. // but when it needs to provide values of its own, it creates its
  815. // own provides object using parent provides object as prototype.
  816. // this way in `inject` we can simply look up injections from direct
  817. // parent and let the prototype chain do the work.
  818. const parentProvides = instance.parent && instance.parent.provides;
  819. if (parentProvides === provides) {
  820. provides = instance.provides = Object.create(parentProvides);
  821. }
  822. // TS doesn't allow symbol as index type
  823. provides[key] = value;
  824. }
  825. }
  826. function initProvide(instance) {
  827. const provideOptions = instance.$options.provide;
  828. if (!provideOptions) {
  829. return;
  830. }
  831. const provides = isFunction(provideOptions)
  832. ? provideOptions.call(instance)
  833. : provideOptions;
  834. const internalInstance = instance.$;
  835. for (const key in provides) {
  836. provide(internalInstance, key, provides[key]);
  837. }
  838. }
  839. function inject(instance, key, defaultValue, treatDefaultAsFactory = false) {
  840. if (instance) {
  841. // #2400
  842. // to support `app.use` plugins,
  843. // fallback to appContext's `provides` if the intance is at root
  844. const provides = instance.parent == null
  845. ? instance.vnode.appContext && instance.vnode.appContext.provides
  846. : instance.parent.provides;
  847. if (provides && key in provides) {
  848. // TS doesn't allow symbol as index type
  849. return provides[key];
  850. }
  851. else if (arguments.length > 1) {
  852. return treatDefaultAsFactory && isFunction(defaultValue)
  853. ? defaultValue()
  854. : defaultValue;
  855. }
  856. else if ((process.env.NODE_ENV !== 'production')) {
  857. console.warn(`injection "${String(key)}" not found.`);
  858. }
  859. }
  860. else if ((process.env.NODE_ENV !== 'production')) {
  861. console.warn(`inject() can only be used inside setup() or functional components.`);
  862. }
  863. }
  864. function initInjections(instance) {
  865. const injectOptions = instance.$options.inject;
  866. if (!injectOptions) {
  867. return;
  868. }
  869. const internalInstance = instance.$;
  870. const ctx = internalInstance.ctx;
  871. if (isArray(injectOptions)) {
  872. for (let i = 0; i < injectOptions.length; i++) {
  873. const key = injectOptions[i];
  874. ctx[key] = inject(internalInstance, key);
  875. }
  876. }
  877. else {
  878. for (const key in injectOptions) {
  879. const opt = injectOptions[key];
  880. let injected;
  881. if (isObject(opt)) {
  882. if ('default' in opt) {
  883. injected = inject(internalInstance, opt.from || key, opt.default, true /* treat default function as factory */);
  884. }
  885. else {
  886. injected = inject(internalInstance, opt.from || key);
  887. }
  888. }
  889. else {
  890. injected = inject(internalInstance, opt);
  891. }
  892. if (isRef(injected)) {
  893. Object.defineProperty(ctx, key, {
  894. enumerable: true,
  895. configurable: true,
  896. get: () => injected.value,
  897. set: (v) => (injected.value = v),
  898. });
  899. }
  900. else {
  901. ctx[key] = injected;
  902. }
  903. }
  904. }
  905. }
  906. // @ts-ignore
  907. function initLifetimes$1({ mocks, isPage, initRelation, vueOptions, }) {
  908. function attached() {
  909. initSetRef(this);
  910. const properties = this.properties;
  911. initVueIds(properties.uI, this);
  912. const relationOptions = {
  913. vuePid: this._$vuePid,
  914. };
  915. // 初始化 vue 实例
  916. const mpInstance = this;
  917. const mpType = isPage(mpInstance) ? 'page' : 'component';
  918. if (mpType === 'page' && !mpInstance.route && mpInstance.__route__) {
  919. mpInstance.route = mpInstance.__route__;
  920. }
  921. const props = findPropsData(properties, mpType === 'page');
  922. this.$vm = $createComponent({
  923. type: vueOptions,
  924. props,
  925. }, {
  926. mpType,
  927. mpInstance,
  928. slots: properties.uS || {},
  929. parentComponent: relationOptions.parent && relationOptions.parent.$,
  930. onBeforeSetup(instance, options) {
  931. initRefs(instance, mpInstance);
  932. initMocks(instance, mpInstance, mocks);
  933. initComponentInstance(instance, options);
  934. },
  935. });
  936. if (mpType === 'component') {
  937. initFormField(this.$vm);
  938. }
  939. if (mpType === 'page') {
  940. if (__VUE_OPTIONS_API__) {
  941. initInjections(this.$vm);
  942. initProvide(this.$vm);
  943. }
  944. }
  945. // 处理父子关系
  946. initRelation(this, relationOptions);
  947. }
  948. function detached() {
  949. if (this.$vm) {
  950. pruneComponentPropsCache(this.$vm.$.uid);
  951. $destroyComponent(this.$vm);
  952. }
  953. }
  954. {
  955. return { attached, detached };
  956. }
  957. }
  958. const mocks = [
  959. '__route__',
  960. '__webviewId__',
  961. '__nodeId__',
  962. '__nodeid__' /* @Deprecated */,
  963. ];
  964. function isPage(mpInstance) {
  965. return (mpInstance.__nodeId__ === 0 || mpInstance.__nodeid__ === 0);
  966. }
  967. const instances = Object.create(null);
  968. function initRelation(mpInstance, detail) {
  969. // 头条 triggerEvent 后,接收事件时机特别晚,已经到了 ready 之后
  970. const nodeId = hasOwn(mpInstance, '__nodeId__')
  971. ? mpInstance.__nodeId__
  972. : mpInstance.__nodeid__;
  973. const webviewId = mpInstance.__webviewId__ + '';
  974. instances[webviewId + '_' + nodeId] = mpInstance.$vm;
  975. mpInstance.triggerEvent('__l', {
  976. vuePid: detail.vuePid,
  977. nodeId,
  978. webviewId,
  979. });
  980. }
  981. function handleLink({ detail: { vuePid, nodeId, webviewId }, }) {
  982. const vm = instances[webviewId + '_' + nodeId];
  983. if (!vm) {
  984. return;
  985. }
  986. let parentVm;
  987. if (vuePid) {
  988. parentVm = findVmByVueId(this.$vm, vuePid);
  989. }
  990. if (!parentVm) {
  991. parentVm = this.$vm;
  992. }
  993. vm.$.parent = parentVm.$;
  994. if (__VUE_OPTIONS_API__) {
  995. parentVm.$children.push(vm);
  996. const parent = parentVm.$;
  997. vm.$.provides = parent
  998. ? parent.provides
  999. : Object.create(parent.appContext.provides);
  1000. initInjections(vm);
  1001. initProvide(vm);
  1002. }
  1003. vm.$callCreatedHook();
  1004. // TODO 字节小程序父子组件关系建立的较晚,导致 inject 和 provide 初始化变慢
  1005. // 由此引发在 setup 中暂不可用,只能通过 options 方式配置
  1006. // 初始化完 inject 后,再次调用 update,触发一次更新
  1007. if (vm.$options.inject) {
  1008. vm.$.update();
  1009. }
  1010. nextSetDataTick(this, () => {
  1011. vm.$callHook('mounted');
  1012. vm.$callHook(ON_READY);
  1013. });
  1014. }
  1015. function parse(componentOptions, { handleLink }) {
  1016. componentOptions.methods.__l = handleLink;
  1017. }
  1018. var parseComponentOptions = /*#__PURE__*/Object.freeze({
  1019. __proto__: null,
  1020. handleLink: handleLink,
  1021. initLifetimes: initLifetimes$1,
  1022. initRelation: initRelation,
  1023. instances: instances,
  1024. isPage: isPage,
  1025. mocks: mocks,
  1026. parse: parse
  1027. });
  1028. function initLifetimes(lifetimesOptions) {
  1029. return extend(initLifetimes$1(lifetimesOptions), {
  1030. ready() {
  1031. if (this.$vm && lifetimesOptions.isPage(this)) {
  1032. if (this.pageinstance) {
  1033. this.__webviewId__ = this.pageinstance.__pageId__;
  1034. }
  1035. this.$vm.$callCreatedHook();
  1036. nextSetDataTick(this, () => {
  1037. this.$vm.$callHook('mounted');
  1038. this.$vm.$callHook(ON_READY);
  1039. });
  1040. }
  1041. else {
  1042. this.is && console.warn(this.is + ' is not ready');
  1043. }
  1044. },
  1045. detached() {
  1046. this.$vm && $destroyComponent(this.$vm);
  1047. // 清理
  1048. const webviewId = this.__webviewId__;
  1049. webviewId &&
  1050. Object.keys(instances).forEach((key) => {
  1051. if (key.indexOf(webviewId + '_') === 0) {
  1052. delete instances[key];
  1053. }
  1054. });
  1055. },
  1056. });
  1057. }
  1058. var parsePageOptions = /*#__PURE__*/Object.freeze({
  1059. __proto__: null,
  1060. handleLink: handleLink,
  1061. initLifetimes: initLifetimes,
  1062. initRelation: initRelation,
  1063. isPage: isPage,
  1064. mocks: mocks,
  1065. parse: parse
  1066. });
  1067. const createApp = initCreateApp();
  1068. const createPage = initCreatePage(parsePageOptions);
  1069. const createComponent = initCreateComponent(parseComponentOptions);
  1070. const createSubpackageApp = initCreateSubpackageApp();
  1071. tt.EventChannel = EventChannel;
  1072. tt.createApp = global.createApp = createApp;
  1073. tt.createPage = createPage;
  1074. tt.createComponent = createComponent;
  1075. tt.createSubpackageApp = global.createSubpackageApp =
  1076. createSubpackageApp;
  1077. export { createApp, createComponent, createPage, createSubpackageApp };