足力健前端,vue版本

mp.js 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  1. import Vue from 'vue';
  2. function parseData (data, vueComponentOptions) {
  3. if (!data) {
  4. return
  5. }
  6. vueComponentOptions.mpOptions.data = data;
  7. }
  8. function parseComponents (vueComponentOptions) {
  9. vueComponentOptions.components = global.__wxVueOptions.components;
  10. }
  11. const _toString = Object.prototype.toString;
  12. const hasOwnProperty = Object.prototype.hasOwnProperty;
  13. function isFn (fn) {
  14. return typeof fn === 'function'
  15. }
  16. function isPlainObject (obj) {
  17. return _toString.call(obj) === '[object Object]'
  18. }
  19. function hasOwn (obj, key) {
  20. return hasOwnProperty.call(obj, key)
  21. }
  22. function noop () {}
  23. /**
  24. * Create a cached version of a pure function.
  25. */
  26. function cached (fn) {
  27. const cache = Object.create(null);
  28. return function cachedFn (str) {
  29. const hit = cache[str];
  30. return hit || (cache[str] = fn(str))
  31. }
  32. }
  33. /**
  34. * Camelize a hyphen-delimited string.
  35. */
  36. const camelizeRE = /-(\w)/g;
  37. const camelize = cached((str) => {
  38. return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
  39. });
  40. const SOURCE_KEY = '__data__';
  41. const COMPONENT_LIFECYCLE = {
  42. created: 'onServiceCreated',
  43. attached: 'onServiceAttached',
  44. ready: 'mounted',
  45. moved: 'moved',
  46. detached: 'destroyed'
  47. };
  48. const COMPONENT_LIFECYCLE_KEYS = Object.keys(COMPONENT_LIFECYCLE);
  49. const PAGE_LIFETIMES = {
  50. show: 'onPageShow',
  51. hide: 'onPageHide',
  52. resize: 'onPageResize'
  53. };
  54. const PAGE_LIFETIMES_KEYS = Object.keys(PAGE_LIFETIMES);
  55. const PAGE_LIFECYCLE = [
  56. 'onLoad',
  57. 'onShow',
  58. 'onReady',
  59. 'onHide',
  60. 'onUnload',
  61. 'onPullDownRefresh',
  62. 'onReachBottom',
  63. 'onShareAppMessage',
  64. 'onPageScroll',
  65. 'onResize',
  66. 'onTabItemTap'
  67. ];
  68. function parsePageMethods (mpComponentOptions, vueComponentOptions) {
  69. const methods = Object.create(null);
  70. Object.keys(mpComponentOptions).forEach(key => {
  71. const value = mpComponentOptions[key];
  72. if (isFn(value) && PAGE_LIFECYCLE.indexOf(key) === -1) {
  73. methods[key] = value;
  74. }
  75. });
  76. vueComponentOptions.methods = methods;
  77. }
  78. function parsePageLifecycle (mpComponentOptions, vueComponentOptions) {
  79. Object.keys(mpComponentOptions).forEach(key => {
  80. if (PAGE_LIFECYCLE.indexOf(key) !== -1) {
  81. vueComponentOptions[key] = mpComponentOptions[key];
  82. }
  83. });
  84. }
  85. function parsePage (mpComponentOptions) {
  86. const vueComponentOptions = {
  87. mixins: [],
  88. mpOptions: {}
  89. };
  90. parseComponents(vueComponentOptions);
  91. parseData(mpComponentOptions.data, vueComponentOptions);
  92. parsePageMethods(mpComponentOptions, vueComponentOptions);
  93. parsePageLifecycle(mpComponentOptions, vueComponentOptions);
  94. return vueComponentOptions
  95. }
  96. function parseProperties (properties, vueComponentOptions) {
  97. if (!properties) {
  98. return
  99. }
  100. vueComponentOptions.mpOptions.properties = properties;
  101. }
  102. function parseOptions (options, vueComponentOptions) {
  103. if (!options) {
  104. return
  105. }
  106. vueComponentOptions.mpOptions.options = options;
  107. }
  108. function parseMethods (methods, vueComponentOptions) {
  109. if (!methods) {
  110. return
  111. }
  112. if (methods.$emit) {
  113. console.warn('Method "$emit" conflicts with an existing Vue instance method');
  114. delete methods.$emit;
  115. }
  116. vueComponentOptions.methods = methods;
  117. }
  118. function parseLifecycle (mpComponentOptions, vueComponentOptions) {
  119. COMPONENT_LIFECYCLE_KEYS.forEach(name => {
  120. if (hasOwn(mpComponentOptions, name)) {
  121. (vueComponentOptions[COMPONENT_LIFECYCLE[name]] || (vueComponentOptions[COMPONENT_LIFECYCLE[name]] = []))
  122. .push(mpComponentOptions[name]);
  123. }
  124. });
  125. }
  126. const mpBehaviors = {
  127. 'wx://form-field': {},
  128. 'wx://component-export': {}
  129. };
  130. function callDefinitionFilter (mpComponentOptions) {
  131. const {
  132. behaviors,
  133. definitionFilter
  134. } = mpComponentOptions;
  135. const behaviorDefinitionFilters = [];
  136. if (Array.isArray(behaviors)) {
  137. behaviors.forEach(behavior => {
  138. behavior = typeof behavior === 'string' ? mpBehaviors[behavior] : behavior;
  139. if (behavior.definitionFilter) {
  140. behaviorDefinitionFilters.push(behavior.definitionFilter);
  141. behavior.definitionFilter.call(null, mpComponentOptions, []);
  142. }
  143. });
  144. }
  145. if (isFn(definitionFilter)) {
  146. return function (defFields) {
  147. definitionFilter(defFields, behaviorDefinitionFilters);
  148. }
  149. }
  150. }
  151. function parseDefinitionFilter (mpComponentOptions, vueComponentOptions) {
  152. callDefinitionFilter(mpComponentOptions);
  153. }
  154. function parseBehavior (behavior) {
  155. const {
  156. data,
  157. methods,
  158. behaviors,
  159. properties
  160. } = behavior;
  161. const vueComponentOptions = {
  162. watch: {},
  163. mpOptions: {
  164. mpObservers: []
  165. }
  166. };
  167. parseData(data, vueComponentOptions);
  168. parseMethods(methods, vueComponentOptions);
  169. parseBehaviors(behaviors, vueComponentOptions);
  170. parseProperties(properties, vueComponentOptions);
  171. parseLifecycle(behavior, vueComponentOptions);
  172. parseDefinitionFilter(behavior);
  173. return vueComponentOptions
  174. }
  175. const BEHAVIORS = {
  176. 'wx://form-field': {
  177. beforeCreate () {
  178. const mpOptions = this.$options.mpOptions;
  179. if (!mpOptions.properties) {
  180. mpOptions.properties = Object.create(null);
  181. }
  182. const props = mpOptions.properties;
  183. // TODO form submit,reset
  184. if (!hasOwn(props, 'name')) {
  185. props.name = {
  186. type: String
  187. };
  188. }
  189. if (!hasOwn(props, 'value')) {
  190. props.value = {
  191. type: String // 默认类型调整为 String,否则默认值为 null,导致一些自定义 input 显示不正确
  192. };
  193. }
  194. }
  195. }
  196. };
  197. function parseBehaviors (behaviors, vueComponentOptions) {
  198. if (!behaviors) {
  199. return
  200. }
  201. behaviors.forEach(behavior => {
  202. if (typeof behavior === 'string') {
  203. BEHAVIORS[behavior] && vueComponentOptions.mixins.push(BEHAVIORS[behavior]);
  204. } else {
  205. vueComponentOptions.mixins.push(parseBehavior(behavior));
  206. }
  207. });
  208. }
  209. function parseSinglePath (path) {
  210. return path.split('.')
  211. }
  212. function parseMultiPaths (paths) {
  213. return paths.split(',').map(path => parseSinglePath(path))
  214. }
  215. function parseObservers (observers, vueComponentOptions) {
  216. if (!observers) {
  217. return
  218. }
  219. const {
  220. mpObservers
  221. } = vueComponentOptions.mpOptions;
  222. Object.keys(observers).forEach(path => {
  223. mpObservers.push({
  224. paths: parseMultiPaths(path),
  225. observer: observers[path]
  226. });
  227. });
  228. }
  229. function relative (from, to) {
  230. if (to.indexOf('/') === 0) {
  231. from = '';
  232. }
  233. const fromArr = from.split('/');
  234. const toArr = to.split('/');
  235. fromArr.pop();
  236. while (toArr.length) {
  237. const part = toArr.shift();
  238. if (part !== '' && part !== '.') {
  239. if (part !== '..') {
  240. fromArr.push(part);
  241. } else {
  242. fromArr.pop();
  243. }
  244. }
  245. }
  246. return fromArr.join('/')
  247. }
  248. function parseRelations (relations, vueComponentOptions) {
  249. if (!relations) {
  250. return
  251. }
  252. Object.keys(relations).forEach(name => {
  253. const relation = relations[name];
  254. relation.name = name;
  255. relation.target = relation.target ? String(relation.target) : relative(global.__wxRoute, name);
  256. });
  257. vueComponentOptions.mpOptions.relations = relations;
  258. }
  259. function parseExternalClasses (externalClasses, vueComponentOptions) {
  260. if (!externalClasses) {
  261. return
  262. }
  263. if (!Array.isArray(externalClasses)) {
  264. externalClasses = [externalClasses];
  265. }
  266. vueComponentOptions.mpOptions.externalClasses = externalClasses;
  267. if (!vueComponentOptions.mpOptions.properties) {
  268. vueComponentOptions.mpOptions.properties = Object.create(null);
  269. }
  270. externalClasses.forEach(externalClass => {
  271. vueComponentOptions.mpOptions.properties[camelize(externalClass)] = {
  272. type: String,
  273. value: ''
  274. };
  275. });
  276. }
  277. function parseLifetimes (lifetimes, vueComponentOptions) {
  278. if (!lifetimes) {
  279. return
  280. }
  281. parseLifecycle(lifetimes, vueComponentOptions);
  282. }
  283. function parsePageLifetimes (pageLifetimes, vueComponentOptions) {
  284. if (!pageLifetimes) {
  285. return
  286. }
  287. PAGE_LIFETIMES_KEYS.forEach(key => {
  288. const lifetimeFn = pageLifetimes[key];
  289. isFn(lifetimeFn) && (vueComponentOptions[PAGE_LIFETIMES[key]] = lifetimeFn);
  290. });
  291. }
  292. function parseComponent (mpComponentOptions) {
  293. const {
  294. data,
  295. options,
  296. methods,
  297. behaviors,
  298. lifetimes,
  299. observers,
  300. relations,
  301. properties,
  302. pageLifetimes,
  303. externalClasses
  304. } = mpComponentOptions;
  305. const vueComponentOptions = {
  306. mixins: [],
  307. props: {},
  308. watch: {},
  309. mpOptions: {
  310. mpObservers: []
  311. }
  312. };
  313. parseComponents(vueComponentOptions);
  314. parseData(data, vueComponentOptions);
  315. parseOptions(options, vueComponentOptions);
  316. parseMethods(methods, vueComponentOptions);
  317. parseBehaviors(behaviors, vueComponentOptions);
  318. parseLifetimes(lifetimes, vueComponentOptions);
  319. parseObservers(observers, vueComponentOptions);
  320. parseRelations(relations, vueComponentOptions);
  321. parseProperties(properties, vueComponentOptions);
  322. parsePageLifetimes(pageLifetimes, vueComponentOptions);
  323. parseExternalClasses(externalClasses, vueComponentOptions);
  324. parseLifecycle(mpComponentOptions, vueComponentOptions);
  325. parseDefinitionFilter(mpComponentOptions);
  326. return vueComponentOptions
  327. }
  328. function initRelationHandlers (type, handler, target, ctx) {
  329. if (!handler) {
  330. return
  331. }
  332. const name = `_$${type}Handlers`;
  333. (ctx[name] || (ctx[name] = [])).push(function () {
  334. handler.call(ctx, target);
  335. });
  336. }
  337. function initLinkedHandlers (relation, target, ctx) {
  338. const type = 'linked';
  339. const name = relation.name;
  340. const relationNodes = ctx._$relationNodes || (ctx._$relationNodes = Object.create(null));
  341. (relationNodes[name] || (relationNodes[name] = [])).push(target);
  342. initRelationHandlers(type, relation[type], target, ctx);
  343. }
  344. function initUnlinkedHandlers (relation, target, ctx) {
  345. const type = 'unlinked';
  346. initRelationHandlers(type, relation[type], target, ctx);
  347. }
  348. function findParentRelation (parentVm, target, type) {
  349. const relations = parentVm &&
  350. parentVm.$options.mpOptions &&
  351. parentVm.$options.mpOptions.relations;
  352. if (!relations) {
  353. return []
  354. }
  355. const name = Object.keys(relations).find(name => {
  356. const relation = relations[name];
  357. return relation.target === target && relation.type === type
  358. });
  359. if (!name) {
  360. return []
  361. }
  362. return [relations[name], parentVm]
  363. }
  364. function initParentRelation (vm, childRelation, match) {
  365. const [parentRelation, parentVm] = match(vm, vm.$options.mpOptions.path);
  366. if (!parentRelation) {
  367. return
  368. }
  369. initLinkedHandlers(parentRelation, vm, parentVm);
  370. initLinkedHandlers(childRelation, parentVm, vm);
  371. initUnlinkedHandlers(parentRelation, vm, parentVm);
  372. initUnlinkedHandlers(childRelation, parentVm, vm);
  373. }
  374. function initRelation (relation, vm) {
  375. const type = relation.type;
  376. if (type === 'parent') {
  377. initParentRelation(vm, relation, function matchParent (vm, target) {
  378. return findParentRelation(vm.$parent, target, 'child')
  379. });
  380. } else if (type === 'ancestor') {
  381. initParentRelation(vm, relation, function matchAncestor (vm, target) {
  382. let $parent = vm.$parent;
  383. while ($parent) {
  384. const ret = findParentRelation($parent, target, 'descendant');
  385. if (ret.length) {
  386. return ret
  387. }
  388. $parent = $parent.$parent;
  389. }
  390. return []
  391. });
  392. }
  393. }
  394. function initRelations (vm) {
  395. const {
  396. relations
  397. } = vm.$options.mpOptions || {};
  398. if (!relations) {
  399. return
  400. }
  401. Object.keys(relations).forEach(name => {
  402. initRelation(relations[name], vm);
  403. });
  404. }
  405. function handleRelations (vm, type) {
  406. // TODO 需要移除 relationNodes
  407. const handlers = vm[`_$${type}Handlers`];
  408. if (!handlers) {
  409. return
  410. }
  411. handlers.forEach(handler => handler());
  412. }
  413. const sharedPropertyDefinition = {
  414. enumerable: true,
  415. configurable: true,
  416. get: noop,
  417. set: noop
  418. };
  419. function proxy (target, sourceKey, key) {
  420. sharedPropertyDefinition.get = function proxyGetter () {
  421. return this[sourceKey][key]
  422. };
  423. sharedPropertyDefinition.set = function proxySetter (val) {
  424. this[sourceKey][key] = val;
  425. };
  426. Object.defineProperty(target, key, sharedPropertyDefinition);
  427. }
  428. function setDataByExprPath (exprPath, value, data) {
  429. const keys = exprPath.replace(/\[(\d+?)\]/g, '.$1').split('.');
  430. keys.reduce((obj, key, idx) => {
  431. if (idx === keys.length - 1) {
  432. obj[key] = value;
  433. } else {
  434. if (typeof obj[key] === 'undefined') {
  435. obj[key] = {};
  436. }
  437. return obj[key]
  438. }
  439. }, data);
  440. return keys.length === 1
  441. }
  442. function setData (data, callback) {
  443. if (!isPlainObject(data)) {
  444. return
  445. }
  446. Object.keys(data).forEach(key => {
  447. if (setDataByExprPath(key, data[key], this.data)) {
  448. !hasOwn(this, key) && proxy(this, SOURCE_KEY, key);
  449. }
  450. });
  451. this.$forceUpdate();
  452. isFn(callback) && this.$nextTick(callback);
  453. }
  454. /**
  455. * https://github.com/swan-team/swan-js/blob/61e2a63f7aa576b5daafbe77fdfa7c65b977060c/src/utils/index.js
  456. */
  457. const _toString$1 = Object.prototype.toString;
  458. /**
  459. * 深度assign的函数
  460. * @param {Object} targetObject 要被拷贝的目标对象
  461. * @param {Object} originObject 拷贝的源对象
  462. * @return {Object} merge后的对象
  463. */
  464. const deepAssign = (targetObject = {}, originObject) => {
  465. const originType = _toString$1.call(originObject);
  466. if (originType === '[object Array]') {
  467. targetObject = originObject.slice(0);
  468. return targetObject
  469. } else if (originType === '[object Object]') {
  470. for (const key in originObject) {
  471. targetObject[key] = deepAssign(targetObject[key], originObject[key]);
  472. }
  473. return targetObject
  474. } else if (originType === '[object Date]') {
  475. return new Date(originObject.getTime())
  476. } else if (originType === '[object RegExp]') {
  477. const target = String(originObject);
  478. const lastIndex = target.lastIndexOf('/');
  479. return new RegExp(target.slice(1, lastIndex), target.slice(lastIndex + 1))
  480. }
  481. return originObject
  482. };
  483. /**
  484. * 深度拷贝逻辑,不同于lodash等库,但是与微信一致
  485. * @param {*} [originObj] 原对象
  486. * @return {Object|Array} 拷贝结果
  487. */
  488. const deepClone = originObj => {
  489. return deepAssign(_toString$1.call(originObj) === '[object Array]' ? [] : {}, originObj)
  490. };
  491. const PROP_DEFAULT_VALUES = {
  492. [String]: '',
  493. [Number]: 0,
  494. [Boolean]: false,
  495. [Object]: null,
  496. [Array]: [],
  497. [null]: null
  498. };
  499. function getDefaultVal (propType) {
  500. return PROP_DEFAULT_VALUES[propType]
  501. }
  502. function getPropertyVal (options) {
  503. if (isPlainObject(options)) {
  504. if (hasOwn(options, 'value')) {
  505. return options.value
  506. }
  507. return getDefaultVal(options.type)
  508. }
  509. return getDefaultVal(options)
  510. }
  511. function getType (propOptions) {
  512. return isPlainObject(propOptions) ? propOptions.type : propOptions
  513. }
  514. function validateProp (key, propsOptions, propsData, vm) {
  515. let value = propsData[key];
  516. if (value !== undefined) {
  517. const propOptions = propsOptions[key];
  518. const type = getType(propOptions);
  519. value = formatVal(value, type);
  520. const observer = propOptions && propOptions.observer;
  521. if (observer) {
  522. // 初始化时,异步触发 observer,否则 observer 中无法访问 methods 或其他
  523. setTimeout(function () {
  524. observe(observer, vm, value);
  525. }, 4);
  526. }
  527. return value
  528. }
  529. return getPropertyVal(propsOptions[key])
  530. }
  531. function formatVal (val, type) {
  532. if (type === Boolean) {
  533. return !!val
  534. } else if (type === String) {
  535. return String(val)
  536. }
  537. return val
  538. }
  539. function observe (observer, vm, newVal, oldVal) {
  540. try {
  541. if (typeof observer === 'function') {
  542. observer.call(vm, newVal, oldVal);
  543. } else if (typeof observer === 'string' &&
  544. typeof vm[observer] === 'function'
  545. ) {
  546. vm[observer](newVal, oldVal);
  547. }
  548. } catch (err) {
  549. console.error(`execute observer ${observer} callback fail! err: ${err}`);
  550. }
  551. }
  552. function initProperties (vm, instanceData) {
  553. const properties = vm.$options.mpOptions.properties;
  554. if (!properties) {
  555. return
  556. }
  557. const propsData = deepClone(vm.$options.propsData) || {};
  558. for (const key in properties) {
  559. const observer = isPlainObject(properties[key]) ? properties[key].observer : false;
  560. let value = validateProp(key, properties, propsData, vm);
  561. Object.defineProperty(instanceData, key, {
  562. enumerable: true,
  563. configurable: true,
  564. get () {
  565. return value
  566. },
  567. set (newVal) {
  568. const oldVal = value;
  569. /* eslint-disable no-self-compare */
  570. if (newVal === value || (newVal !== newVal && value !== value)) {
  571. return
  572. }
  573. // TODO 临时方案,clone array
  574. value = Array.isArray(newVal) ? newVal.slice(0) : newVal;
  575. if (observer) {
  576. observe(observer, vm, newVal, oldVal);
  577. }
  578. // 触发渲染
  579. vm.$forceUpdate();
  580. }
  581. });
  582. }
  583. }
  584. function updateProperties (vm) {
  585. const properties = vm.$options.mpOptions && vm.$options.mpOptions.properties;
  586. const propsData = vm.$options.propsData;
  587. if (propsData && properties) {
  588. Object.keys(properties).forEach(key => {
  589. if (hasOwn(propsData, key)) {
  590. vm[key] = formatVal(propsData[key], getType(properties[key]));
  591. }
  592. });
  593. }
  594. }
  595. function initState (vm) {
  596. const instanceData = JSON.parse(JSON.stringify(vm.$options.mpOptions.data || {}));
  597. vm[SOURCE_KEY] = instanceData;
  598. const propertyDefinition = {
  599. get () {
  600. return vm[SOURCE_KEY]
  601. },
  602. set (value) {
  603. vm[SOURCE_KEY] = value;
  604. }
  605. };
  606. Object.defineProperties(vm, {
  607. data: propertyDefinition,
  608. properties: propertyDefinition
  609. });
  610. vm.setData = setData;
  611. initProperties(vm, instanceData);
  612. Object.keys(instanceData).forEach(key => {
  613. proxy(vm, SOURCE_KEY, key);
  614. });
  615. }
  616. function initMethods (vm) {
  617. const oldEmit = vm.$emit;
  618. vm.triggerEvent = (eventName, detail, options) => {
  619. const target = {
  620. dataset: vm.$el.dataset
  621. };
  622. const event = {
  623. target,
  624. currentTarget: target,
  625. detail,
  626. preventDefault: noop,
  627. stopPropagation: noop
  628. };
  629. oldEmit.call(vm, eventName, event);
  630. };
  631. // 主要是Vant 自己封装了 $emit,放到 methods 中会触发 Vue 的警告,索性,框架直接重写该方法
  632. vm.$emit = (...args) => {
  633. vm.triggerEvent(...args);
  634. };
  635. vm.getRelationNodes = (relationKey) => {
  636. // 需要过滤已被销毁的vm
  637. /* eslint-disable no-mixed-operators */
  638. return (vm._$relationNodes && vm._$relationNodes[relationKey] || []).filter(vm => !vm._isDestroyed)
  639. };
  640. vm._$updateProperties = updateProperties;
  641. }
  642. function handleObservers (vm) {
  643. const watch = vm.$options.watch;
  644. if (!watch) {
  645. return
  646. }
  647. Object.keys(watch).forEach(name => {
  648. const observer = watch[name];
  649. if (observer.mounted) {
  650. const val = vm[name];
  651. let handler = observer.handler;
  652. if (typeof handler === 'string') {
  653. handler = vm[handler];
  654. }
  655. handler && handler.call(vm, val, val);
  656. }
  657. });
  658. }
  659. var polyfill = {
  660. beforeCreate () {
  661. // 取消 development 时的 Proxy,避免小程序组件模板中使用尚未定义的属性告警
  662. this._renderProxy = this;
  663. this._$self = this;
  664. this._$noop = noop;
  665. },
  666. created () { // properties 中可能会访问 methods,故需要在 created 中初始化
  667. initState(this);
  668. initMethods(this);
  669. initRelations(this);
  670. },
  671. mounted () {
  672. handleObservers(this);
  673. },
  674. destroyed () {
  675. handleRelations(this, 'unlinked');
  676. }
  677. };
  678. global.__wxRoute = '';
  679. global.__wxComponents = Object.create(null);
  680. global.__wxVueOptions = Object.create(null);
  681. function Page (options) {
  682. const pageOptions = parsePage(options);
  683. pageOptions.mixins.unshift(polyfill);
  684. pageOptions.mpOptions.path = global.__wxRoute;
  685. global.__wxComponents[global.__wxRoute] = pageOptions;
  686. }
  687. function initRelationsHandler (vueComponentOptions) {
  688. // linked 需要在当前组件 attached 之后再执行
  689. if (!vueComponentOptions.onServiceAttached) {
  690. vueComponentOptions.onServiceAttached = [];
  691. }
  692. vueComponentOptions.onServiceAttached.push(function onServiceAttached () {
  693. handleRelations(this, 'linked');
  694. });
  695. }
  696. function Component (options) {
  697. const componentOptions = parseComponent(options);
  698. componentOptions.mixins.unshift(polyfill);
  699. componentOptions.mpOptions.path = global.__wxRoute;
  700. initRelationsHandler(componentOptions);
  701. global.__wxComponents[global.__wxRoute] = componentOptions;
  702. }
  703. function Behavior (options) {
  704. return options
  705. }
  706. const nextTick = Vue.nextTick;
  707. var index = uni.__$wx__;
  708. export default index;
  709. export { Behavior, Component, Page, nextTick };