mini mvvm

自用,bug较多,if和for指令不能使用

目前为 2022-05-06 提交的版本,查看 最新版本

此脚本不应直接安装,它是供其他脚本使用的外部库。如果你需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/444466/1047660/mini%20mvvm.js

  1. // ==UserScript==
  2. // @name mini mvvm
  3. // @namespace Violentmonkey Scripts
  4. // @match *://*/*
  5. // @grant none
  6. // @version 0.0.2
  7. // @author -
  8. // @description 自用,bug较多,if和for指令不能使用
  9. // ==/UserScript==
  10. function* getSequence() {
  11. let i = 0;
  12. while (true) {
  13. yield (i = i + 1);
  14. }
  15. }
  16. let sequence = getSequence();
  17. function getId(name) {
  18. return `${name ? name : 'none'}.${new Date().getTime()}.${Math.floor(Math.random() * 10000)}.${sequence.next().value}`;
  19. }
  20. class Dep {
  21. constructor(name) {
  22. this.subs = [];
  23. this.id = getId(name);
  24. }
  25. delete() {
  26. if (this.subs.length < 1)
  27. return;
  28. this.notify();
  29. this.subs.forEach((sub) => {
  30. sub.removeDep(this);
  31. });
  32. this.subs.length = 0;
  33. }
  34. addSub(sub) {
  35. this.subs.push(sub);
  36. }
  37. depend() {
  38. Dep.target.addDep(this);
  39. }
  40. notify() {
  41. this.subs.forEach((sub) => {
  42. sub.update();
  43. });
  44. }
  45. }
  46. Dep.target = null;
  47.  
  48. const extend = (a, b) => {
  49. for (const key in b) {
  50. a[key] = b[key];
  51. }
  52. return a;
  53. };
  54. const isFunction = (val) => typeof val === 'function';
  55. const NOOP = () => { };
  56. const objectToString = Object.prototype.toString;
  57. const toTypeString = (value) => objectToString.call(value);
  58. const isPlainObject = (val) => toTypeString(val) === '[object Object]';
  59. const hasOwnProperty = Object.prototype.hasOwnProperty;
  60. const hasOwn = (val, key) => hasOwnProperty.call(val, key);
  61. function toArray(nodes) {
  62. return [].slice.call(nodes);
  63. }
  64. const unique = (arr) => Array.from(new Set(arr));
  65.  
  66. function observe(value, vm) {
  67. if (!value || typeof value !== 'object')
  68. return value;
  69. if(value.__ob__)
  70. return value
  71. return new Observer(value, vm).proxy;
  72. }
  73. class Observer {
  74. constructor(data, vm) {
  75. Object.keys(data).forEach((key) => {
  76. data[key] = observe(data[key], vm);
  77. });
  78. this.dep = new Dep('data');
  79. Object.defineProperty(data, '__ob__', {
  80. configurable: false,
  81. enumerable: false,
  82. value:this
  83. })
  84. this.proxy = new Proxy(data, {
  85. get: (target, key, receiver) => {
  86. const result = Reflect.get(target, key, receiver)
  87. if (Dep.target){
  88. if(isPlainObject(result) && result.__ob__)
  89. result.__ob__.dep.depend()
  90. else
  91. this.dep.depend()
  92. }
  93. return result;
  94. },
  95. set: (target, key, newValue, receiver) => {
  96. const result = Reflect.set(target, key, observe(newValue), receiver);
  97. this.dep.notify();
  98. return result;
  99. },
  100. deleteProperty: (target, key) => {
  101. const childObj = target[key];
  102. let result = false;
  103. if (isPlainObject(childObj) && hasOwn(childObj, '__ob__')) {
  104. let ob = childObj['__ob__'];
  105. ob.dep.delete();
  106. ob = null;
  107. result = Reflect.deleteProperty(target, key);
  108. this.dep.notify();
  109. }
  110. return result;
  111. },
  112. });
  113. }
  114. }
  115.  
  116. class EventEmitter {
  117. constructor(scope) {
  118. this._events = new Map();
  119. if (scope)
  120. this._scope = scope;
  121. }
  122. has(eventName){
  123. return this._events.has(eventName)
  124. }
  125. on(eventName, callback) {
  126. if (!this._events.has(eventName))
  127. this._events.set(eventName, []);
  128. this._events.get(eventName).push(callback);
  129. }
  130. emit(eventName, value) {
  131. if (!this._events.has(eventName))
  132. return;
  133. this._events.get(eventName).forEach((callback) => {
  134. if (isFunction(callback))
  135. callback(value);
  136. });
  137. }
  138. off(eventName, callback) {
  139. if (callback) {
  140. this._events.set(eventName, this._events.get(eventName).filter((cb) => {
  141. if (cb === callback || cb.originFunction === callback)
  142. return false;
  143. }));
  144. }
  145. else {
  146. this._events.delete(eventName);
  147. }
  148. }
  149. once(eventName, callback) {
  150. const self = this;
  151. const onceCallback = function () {
  152. self.off(eventName, onceCallback);
  153. callback.apply(self, arguments);
  154. };
  155. onceCallback.originFunction = callback;
  156. this.on(eventName, onceCallback);
  157. }
  158. }
  159.  
  160. var EventLoop;
  161. (function (EventLoop) {
  162. const callbacks = [];
  163. const p = Promise.resolve();
  164. let pending = false;
  165. let useMacroTask = false;
  166. function flushCallbacks() {
  167. pending = false;
  168. const copies = callbacks.slice(0);
  169. callbacks.length = 0;
  170. copies.forEach((fn) => fn());
  171. }
  172. EventLoop.flushCallbacks = flushCallbacks;
  173. const macroTimerFunction = () => {
  174. setTimeout(flushCallbacks, 0);
  175. };
  176. const microTimerFunction = () => {
  177. p.then(flushCallbacks);
  178. };
  179. function withMacroTask(fn) {
  180. return (fn._withTask ||
  181. (fn._withTask = function () {
  182. useMacroTask = true;
  183. const res = fn.apply(null, arguments);
  184. useMacroTask = false;
  185. return res;
  186. }));
  187. }
  188. EventLoop.withMacroTask = withMacroTask;
  189. function nextTick(context, callback) {
  190. let _resolve;
  191. callbacks.push(() => {
  192. if (callback)
  193. callback.call(context);
  194. else if (_resolve)
  195. _resolve(context);
  196. });
  197. if (!pending) {
  198. pending = true;
  199. if (useMacroTask)
  200. macroTimerFunction();
  201. else
  202. microTimerFunction();
  203. }
  204. if (!callback)
  205. return new Promise((resolve) => {
  206. _resolve = resolve;
  207. });
  208. }
  209. EventLoop.nextTick = nextTick;
  210. })(EventLoop || (EventLoop = {}));
  211.  
  212. function getApplyFunction(fn, scope) {
  213. const func = function () {
  214. fn.apply(scope, arguments);
  215. };
  216. return func;
  217. }
  218. const createVM = (options = {}) => new MVVM(extend(options, {
  219. element: options.element ? options.element : document.body
  220. }));
  221. class MVVM {
  222. constructor(options = {}) {
  223. this.$event = new EventEmitter(this);
  224. this.$children = {};
  225. this.$refs = {};
  226. this.$on = getApplyFunction(this.$event.on, this.$event);
  227. this.$emit = getApplyFunction(this.$event.emit, this.$event);
  228. this.$off = getApplyFunction(this.$event.off, this.$event);
  229. this.$once = getApplyFunction(this.$event.once, this.$event);
  230. this.$options = options;
  231. this.components = options.components;
  232. MVVM.cid += 1;
  233. this.cid = MVVM.cid;
  234. this._init();
  235. if (this.$options.element)
  236. this.compile(this.$options.element);
  237. }
  238. $watch(key, cb) {
  239. new Watcher(this, key, cb);
  240. }
  241. $nextTick(callback) {
  242. if (callback)
  243. return EventLoop.nextTick(this, callback);
  244. return EventLoop.nextTick(this);
  245. }
  246. use(fn) {
  247. fn.call(this, this);
  248. return this;
  249. }
  250. compile(element) {
  251. this.$compile = new Compile(element, this);
  252. this.$emit('mounted');
  253. }
  254. _init() {
  255. this._initMethods();
  256. this._initLifecycle();
  257. this.$emit('beforeCreate');
  258. this._initData();
  259. this._initComputed();
  260. this._initWatch();
  261. this.$emit('created');
  262. }
  263. _initMethods() {
  264. let methods = this.$options.methods;
  265. if (typeof methods !== 'object')
  266. return;
  267. Object.keys(methods).forEach((key) => {
  268. let object = methods[key];
  269. if (!isFunction(object))
  270. return;
  271. if (this[key])
  272. return;
  273. this[key] = object;
  274. });
  275. }
  276. _initLifecycle() {
  277. this.$options.beforeCreate &&
  278. this.$on('beforeCreate', this.$options.beforeCreate.bind(this));
  279. this.$options.created && this.$on('created', this.$options.created.bind(this));
  280. this.$options.beforeMount &&
  281. this.$on('beforeMount', this.$options.beforeMount);
  282. this.$options.mounted && this.$on('mounted', this.$options.mounted.bind(this));
  283. this.$options.beforeUpdate &&
  284. this.$on('beforeUpdate', this.$options.beforeUpdate);
  285. this.$options.updated && this.$on('updated', this.$options.updated.bind(this));
  286. }
  287. _initData() {
  288. const data = this.$options.data;
  289. this.$data = isFunction(data) ? data.call(this) : data;
  290. Object.keys(this.$data).forEach((key) => Object.defineProperty(this, key, {
  291. configurable: false,
  292. enumerable: true,
  293. get: () => {
  294. return this.$data[key];
  295. },
  296. set: (newVal) => {
  297. this.$data[key] = newVal;
  298. },
  299. }));
  300. this.$data = observe(this.$data, this);
  301. }
  302. _initComputed() {
  303. let computed = this.$options.computed;
  304. if (!isPlainObject(computed))
  305. return;
  306. Object.keys(computed).forEach((key) => {
  307. let object = computed[key];
  308. Object.defineProperty(this, key, {
  309. get: isFunction(object)
  310. ? object
  311. : 'get' in object
  312. ? object.get
  313. : NOOP,
  314. set: isFunction(object)
  315. ? object
  316. : 'set' in object
  317. ? object.set
  318. : NOOP,
  319. });
  320. });
  321. }
  322. _initWatch() {
  323. let watch = this.$options.watch;
  324. if (typeof watch !== 'object')
  325. return;
  326. Object.keys(watch).forEach((key) => {
  327. let object = watch[key];
  328. if (!isFunction(object))
  329. return;
  330. this.$watch(key, object);
  331. });
  332. }
  333. }
  334. MVVM.cid = 0;
  335. function getVMVal(vm, exp) {
  336. let temp;
  337. exp.split('.').forEach((k, i) => {
  338. if (i === 0)
  339. temp = vm[k];
  340. else
  341. temp = temp[k];
  342. });
  343. return temp;
  344. }
  345. function setVMVal(vm, exp, value) {
  346. let temp;
  347. let exps = exp.split('.');
  348. if (exps.length === 1)
  349. vm[exps[0]] = value;
  350. else
  351. exps.forEach((k, i, exps) => {
  352. if (i === 0)
  353. temp = vm[k];
  354. else if (i < exps.length - 1)
  355. temp = temp[k];
  356. else if (i === exps.length - 1)
  357. temp[k] = value;
  358. });
  359. }
  360.  
  361. function parseGetter(exp) {
  362. return (vm) => getVMVal(vm, exp);
  363. }
  364. class Watcher {
  365. constructor(vm, expOrFn, callback,deep = false) {
  366. this.callback = callback;
  367. this.vm = vm;
  368. this.deep = deep
  369. this._depIds = {};
  370. if (isFunction(expOrFn))
  371. this._getter = expOrFn;
  372. else
  373. this._getter = parseGetter(expOrFn.trim());
  374. this.value = this.get();
  375. }
  376. update() {
  377. let newVal = this.get();
  378. let oldVal = this.value;
  379. if (newVal === oldVal && !(this.deep && isPlainObject(newVal) && isPlainObject(oldVal))) return
  380. this.value = newVal;
  381. this.callback.call(this.vm, newVal, oldVal);
  382. }
  383. removeDep(dep) {
  384. delete this._depIds[dep.id];
  385. }
  386. addDep(dep) {
  387. if (!hasOwn(this._depIds, dep.id)) {
  388. dep.addSub(this);
  389. this._depIds[dep.id] = dep;
  390. }
  391. }
  392. get() {
  393. Dep.target = this;
  394. let value = this._getter.call(this.vm, this.vm);
  395. Dep.target = null;
  396. return value;
  397. }
  398. }
  399.  
  400. class ElementUtility {
  401. static fragment(el) {
  402. let fragment = document.createDocumentFragment(), child;
  403. while ((child = el.firstChild))
  404. fragment.appendChild(child);
  405. return fragment;
  406. }
  407. static parseHTML(html) {
  408. const domParser = new DOMParser();
  409. let temp = domParser.parseFromString(html, 'text/html');
  410. return temp.body.children;
  411. }
  412. static isElementNode(node) {
  413. if (node instanceof Element)
  414. return node.nodeType == 1;
  415. return false;
  416. }
  417. static isTextNode(node) {
  418. if (node instanceof Text)
  419. return node.nodeType == 3;
  420. return false;
  421. }
  422. static text(node, value) {
  423. if (typeof value === 'number')
  424. value = String(value);
  425. node.textContent = value ? value : '';
  426. }
  427. static html(node, value) {
  428. if (typeof value === 'number')
  429. value = String(value);
  430. node.innerHTML = value ? value : '';
  431. }
  432. static class(node, value, oldValue) {
  433. let className = node.className;
  434. className = className.replace(oldValue, '').replace(/\s$/, '');
  435. let space = className && String(value) ? ' ' : '';
  436. node.className = className + space + value;
  437. }
  438. static model(node, newValue) {
  439. if (typeof newValue === 'number')
  440. newValue = String(newValue);
  441. node.value = newValue ? newValue : '';
  442. }
  443. static style(node, newValue, oldValue) {
  444. if (!oldValue)
  445. oldValue = {};
  446. if (!newValue)
  447. newValue = {};
  448. const keys = Object.keys(oldValue).concat(Object.keys(newValue));
  449. unique(keys).forEach((key) => {
  450. if (hasOwn(oldValue, key) && hasOwn(newValue, key)) {
  451. if (oldValue[key] != newValue[key])
  452. node.style.setProperty(key, newValue[key]);
  453. }
  454. else if (hasOwn(newValue, key))
  455. node.style.setProperty(key, newValue[key]);
  456. else
  457. node.style.removeProperty(key);
  458. });
  459. }
  460. static display(node, newValue, oldValue) {
  461. let func = (val) => {
  462. return {
  463. display: val ? 'block' : 'none',
  464. };
  465. };
  466. ElementUtility.style(node, func(newValue), null);
  467. }
  468. }
  469.  
  470. class MVVMComponent extends MVVM {
  471. constructor(options) {
  472. super(options);
  473. this.$template = options.template || '';
  474. if (options.parent)
  475. this.$parent = options.parent;
  476. }
  477. $mount(element) {
  478. this.compile(element);
  479. }
  480. }
  481. const mountComponent = (element,component) => {
  482. const vm = new MVVMComponent(component)
  483. vm.$mount(element)
  484. return vm
  485. }
  486.  
  487. const parseAnyDirectiveFunction = (parseString) => {
  488. return (dir) => dir.indexOf(parseString) == 0;
  489. };
  490. const isDirective = parseAnyDirectiveFunction('v-');
  491. const isEventDirective = parseAnyDirectiveFunction('on');
  492. const isTextDirective = parseAnyDirectiveFunction('text');
  493. const isHtmlDirective = parseAnyDirectiveFunction('html');
  494. const isModelDirective = parseAnyDirectiveFunction('model');
  495. const isClassDirective = parseAnyDirectiveFunction('class');
  496. const isStyleDirective = parseAnyDirectiveFunction('style');
  497. const isShowDirective = parseAnyDirectiveFunction('show');
  498. const isRefDirective = parseAnyDirectiveFunction('ref');
  499. const isForDirective = parseAnyDirectiveFunction('for');
  500.  
  501. function bindWatcher(node, vm, exp, updater) {
  502. let __for__ = node['__for__'];
  503. let val;
  504. if (__for__ && __for__[exp])
  505. val = __for__[exp]
  506. else
  507. val = getVMVal(vm, exp);
  508. updater && updater(node, val);
  509. new Watcher(vm, exp, (newValue, oldValue) => {
  510. if (newValue === oldValue)
  511. return;
  512. updater && updater(node, newValue, oldValue);
  513. });
  514. }
  515. function eventHandler(node, vm, exp, eventType) {
  516. let fn = vm.$options.methods && vm.$options.methods[exp];
  517. if (eventType && fn) {
  518. if(node instanceof MVVMComponent)
  519. node.$on(eventType,fn.bind(vm))
  520. else
  521. node.addEventListener(eventType, fn.bind(vm), false);
  522. }
  523. }
  524. function vFor(node, vm, exp, c) {
  525. let reg = /\((.*)\)/;
  526. let item, index, list;
  527. if (reg.test(exp)) {
  528. const arr = RegExp.$1.trim().split(',');
  529. item = arr[0];
  530. index = arr[1];
  531. let rightString = RegExp.rightContext.trim();
  532. let rarr = rightString.split(' ');
  533. list = rarr[1];
  534. if (rarr[0] !== 'in')
  535. return;
  536. let val = getVMVal(vm, list);
  537. let children = [];
  538. toArray(node.children).forEach((element) => {
  539. children.push(element.cloneNode(true));
  540. node.removeChild(element);
  541. });
  542. for (let i = 0; i < val.length; i++) {
  543. children.forEach((element) => {
  544. let newNode = element.cloneNode(true);
  545. newNode.__for__ = {
  546. [item]: val[i],
  547. [index]: i
  548. };
  549. node.appendChild(newNode);
  550. c.compileElement(node);
  551. });
  552. }
  553. }
  554. }
  555. function forHandler(node, vm, exp, c) {
  556. vFor(node, vm, exp, c);
  557. new Watcher(vm, exp, (newValue, oldValue) => {
  558. if (newValue === oldValue)
  559. return;
  560. vFor(node, vm, exp, c);
  561. });
  562. }
  563. class Compile {
  564. constructor(el, vm) {
  565. this.slotCallback = [];
  566. this.$vm = vm;
  567. this.$el = ElementUtility.isElementNode(el)
  568. ? el
  569. : document.querySelector(el);
  570. this._init();
  571. }
  572. _init() {
  573. if (this.$vm instanceof MVVMComponent) {
  574. this.$slot = ElementUtility.fragment(this.$el);
  575. this.$fragment = this.parseComponentTemplate(this.$vm.$template);
  576. this.$vm.$el = this.$el;
  577. this.$vm.$emit('beforeMount');
  578. this.compileElement(this.$fragment);
  579. this.$el.parentNode.replaceChild(this.$fragment, this.$el);
  580. }
  581. else {
  582. this.$fragment = ElementUtility.fragment(this.$el);
  583. this.$vm.$el = this.$el;
  584. this.$vm.$emit('beforeMount');
  585. this.compileElement(this.$fragment);
  586. this.$el.appendChild(this.$fragment);
  587. }
  588. Object.entries(this.$vm.$children).forEach(([key, child]) => {
  589. const slotCallback = child.$compile.slotCallback;
  590. if (slotCallback.length < 1)
  591. return;
  592. slotCallback.forEach((fn) => {
  593. fn(this);
  594. });
  595. });
  596. }
  597. isSlot(node) {
  598. if (node.tagName === 'SLOT')
  599. return true;
  600. return false;
  601. }
  602. compileSlotElement(slot) {
  603. if (!(this.$vm instanceof MVVMComponent))
  604. return;
  605. if (this.$slot.children.length === 0) {
  606. slot.parentNode.removeChild(slot);
  607. return;
  608. }
  609. this.slotCallback.push(c => {
  610. c.compileElement(this.$slot);
  611. slot.parentNode.replaceChild(this.$slot, slot);
  612. });
  613. }
  614. parseComponentTemplate(templateHTML) {
  615. let element = ElementUtility.parseHTML(templateHTML);
  616. const template = document.createElement('template');
  617. if (element.length) {
  618. if (element.length === 1) {
  619. if (element[0].tagName.toLowerCase() !== 'template')
  620. template.appendChild(element[0]);
  621. }
  622. else
  623. toArray(element).forEach((child) => {
  624. template.appendChild(child);
  625. });
  626. }
  627. return ElementUtility.fragment(template);
  628. }
  629. parseTemplate(leftString, rightString) {
  630. return (node, newValue, oldValue) => {
  631. const str = leftString + newValue + rightString;
  632. ElementUtility.text(node, str);
  633. };
  634. }
  635. compileElement(el) {
  636. let childNodes = [];
  637. // slice
  638. el.childNodes.forEach(node=>{
  639. childNodes.push(node)
  640. })
  641. childNodes.forEach((node) => {
  642. if (el['__for__'])
  643. node['__for__'] = el['__for__'];
  644. let reg = /\{\{(.*)\}\}/;
  645. if (ElementUtility.isElementNode(node)) {
  646. if (this.isComponent(node))
  647. this.compileComponent(node.tagName.toLowerCase(), node);
  648. else if (this.isSlot(node))
  649. this.compileSlotElement(node);
  650. else
  651. this.compile(node);
  652. }
  653. else if (ElementUtility.isTextNode(node) &&
  654. reg.test(node.textContent))
  655. bindWatcher(node, this.$vm, RegExp.$1.trim(), this.parseTemplate(RegExp.leftContext, RegExp.rightContext));
  656. if (node.childNodes && node.childNodes.length)
  657. this.compileElement(node);
  658. });
  659. }
  660. compile(node) {
  661. let nodeAttrs = node.attributes;
  662. toArray(nodeAttrs).forEach((attr) => {
  663. let attrName = attr.name;
  664. if (!isDirective(attrName)){
  665. if (attrName.startsWith('[') && attrName.endsWith(']')) {
  666. node.removeAttribute(attrName)
  667. let realAttrName = attrName.replace('[','')
  668. realAttrName = realAttrName.replace(']','')
  669. bindWatcher(node,this.$vm,attr.value,(node,newVal,oldVal)=>{
  670. node.setAttribute(realAttrName,newVal)
  671. })
  672. }
  673. return;
  674. }
  675. let dir = attrName.substring(2);
  676. let suffix = dir.split(':')[1];
  677. let exp = attr.value || suffix;
  678. if (isEventDirective(dir))
  679. eventHandler(node, this.$vm, exp, suffix);
  680. else if (isTextDirective(dir))
  681. bindWatcher(node, this.$vm, exp, ElementUtility.text);
  682. else if (isHtmlDirective(dir))
  683. bindWatcher(node, this.$vm, exp, ElementUtility.html);
  684. else if (isClassDirective(dir))
  685. bindWatcher(node, this.$vm, exp, ElementUtility.class);
  686. else if (isModelDirective(dir)) {
  687. bindWatcher(node, this.$vm, exp, ElementUtility.model);
  688. let val = getVMVal(this.$vm, exp);
  689. node.addEventListener('input', (e) => {
  690. let target = e.target;
  691. let newValue = target.value;
  692. if (val === newValue)
  693. return;
  694. setVMVal(this.$vm, exp, newValue);
  695. val = newValue;
  696. });
  697. }
  698. else if (isStyleDirective(dir))
  699. bindWatcher(node, this.$vm, exp, ElementUtility.style);
  700. else if (isShowDirective(dir))
  701. bindWatcher(node, this.$vm, exp, ElementUtility.display);
  702. else if (isRefDirective(dir))
  703. this.$vm.$refs[exp] = node;
  704. else if (isForDirective(dir))
  705. forHandler(node, this.$vm, exp, this);
  706. node.removeAttribute(attrName);
  707. });
  708. }
  709. isComponent(node) {
  710. const tagName = node.tagName.toLowerCase();
  711. if (!/^[(a-zA-Z)-]*$/.test(tagName))
  712. return false;
  713. if (this.$vm.components && hasOwn(this.$vm.components, tagName))
  714. return true;
  715. return false;
  716. }
  717. compileComponent(componentName, node) {
  718. const attributes = []
  719. toArray(node.attributes).forEach((attr) => {
  720. attributes.push(attr)
  721. })
  722. const componentOptions = this.$vm.components[componentName];
  723. const component = new MVVMComponent(extend(componentOptions, {
  724. parent: this.$vm
  725. }));
  726. component.$mount(node);
  727. this.$vm.$children[componentName] = component;
  728. attributes.forEach(attr=>{
  729. let attrName = attr.name;
  730. if (!isDirective(attrName))
  731. return;
  732. let dir = attrName.substring(2);
  733. let suffix = dir.split(':')[1];
  734. let exp = attr.value || suffix;
  735. if (isEventDirective(dir))
  736. eventHandler(component, this.$vm, exp, suffix);
  737. else if (isRefDirective(dir))
  738. this.$vm.$refs[exp] = component;
  739. })
  740. }
  741. }