mini mvvm

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

目前為 2022-05-07 提交的版本,檢視 最新版本

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.cn-greasyfork.org/scripts/444466/1047822/mini%20mvvm.js

  1. // ==UserScript==
  2. // @name mini mvvm
  3. // @namespace Violentmonkey Scripts
  4. // @match *://*/*
  5. // @grant none
  6. // @version 0.0.3
  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. static mount(component,element) {
  481. const vm = new MVVMComponent(component)
  482. vm.$mount(element)
  483. return vm
  484. }
  485.  
  486. static appendChild(component,element){
  487. const div = document.createElement('div')
  488. element.appendChild(div)
  489. return MVVMComponent.mount(component,div)
  490. }
  491. }
  492.  
  493. const parseAnyDirectiveFunction = (parseString) => {
  494. return (dir) => dir.indexOf(parseString) == 0;
  495. };
  496. const isDirective = parseAnyDirectiveFunction('v-');
  497. const isEventDirective = parseAnyDirectiveFunction('on');
  498. const isTextDirective = parseAnyDirectiveFunction('text');
  499. const isHtmlDirective = parseAnyDirectiveFunction('html');
  500. const isModelDirective = parseAnyDirectiveFunction('model');
  501. const isClassDirective = parseAnyDirectiveFunction('class');
  502. const isStyleDirective = parseAnyDirectiveFunction('style');
  503. const isShowDirective = parseAnyDirectiveFunction('show');
  504. const isRefDirective = parseAnyDirectiveFunction('ref');
  505. const isForDirective = parseAnyDirectiveFunction('for');
  506.  
  507. function bindWatcher(node, vm, exp, updater) {
  508. let __for__ = node['__for__'];
  509. let val;
  510. if (__for__ && __for__[exp])
  511. val = __for__[exp]
  512. else
  513. val = getVMVal(vm, exp);
  514. updater && updater(node, val);
  515. new Watcher(vm, exp, (newValue, oldValue) => {
  516. if (newValue === oldValue)
  517. return;
  518. updater && updater(node, newValue, oldValue);
  519. });
  520. }
  521. function eventHandler(node, vm, exp, eventType) {
  522. let fn = vm.$options.methods && vm.$options.methods[exp];
  523. if (eventType && fn) {
  524. if(node instanceof MVVMComponent)
  525. node.$on(eventType,fn.bind(vm))
  526. else
  527. node.addEventListener(eventType, fn.bind(vm), false);
  528. }
  529. }
  530. function vFor(node, vm, exp, c) {
  531. let reg = /\((.*)\)/;
  532. let item, index, list;
  533. if (reg.test(exp)) {
  534. const arr = RegExp.$1.trim().split(',');
  535. item = arr[0];
  536. index = arr[1];
  537. let rightString = RegExp.rightContext.trim();
  538. let rarr = rightString.split(' ');
  539. list = rarr[1];
  540. if (rarr[0] !== 'in')
  541. return;
  542. let val = getVMVal(vm, list);
  543. let children = [];
  544. toArray(node.children).forEach((element) => {
  545. children.push(element.cloneNode(true));
  546. node.removeChild(element);
  547. });
  548. for (let i = 0; i < val.length; i++) {
  549. children.forEach((element) => {
  550. let newNode = element.cloneNode(true);
  551. newNode.__for__ = {
  552. [item]: val[i],
  553. [index]: i
  554. };
  555. node.appendChild(newNode);
  556. c.compileElement(node);
  557. });
  558. }
  559. }
  560. }
  561. function forHandler(node, vm, exp, c) {
  562. vFor(node, vm, exp, c);
  563. new Watcher(vm, exp, (newValue, oldValue) => {
  564. if (newValue === oldValue)
  565. return;
  566. vFor(node, vm, exp, c);
  567. });
  568. }
  569. class Compile {
  570. constructor(el, vm) {
  571. this.slotCallback = [];
  572. this.$vm = vm;
  573. this.$el = ElementUtility.isElementNode(el)
  574. ? el
  575. : document.querySelector(el);
  576. this._init();
  577. }
  578. _init() {
  579. if (this.$vm instanceof MVVMComponent) {
  580. this.$slot = ElementUtility.fragment(this.$el);
  581. this.$fragment = this.parseComponentTemplate(this.$vm.$template);
  582. this.$vm.$el = this.$el;
  583. this.$vm.$emit('beforeMount');
  584. this.compileElement(this.$fragment);
  585. this.$el.parentNode.replaceChild(this.$fragment, this.$el);
  586. }
  587. else {
  588. this.$fragment = ElementUtility.fragment(this.$el);
  589. this.$vm.$el = this.$el;
  590. this.$vm.$emit('beforeMount');
  591. this.compileElement(this.$fragment);
  592. this.$el.appendChild(this.$fragment);
  593. }
  594. Object.entries(this.$vm.$children).forEach(([key, child]) => {
  595. const slotCallback = child.$compile.slotCallback;
  596. if (slotCallback.length < 1)
  597. return;
  598. slotCallback.forEach((fn) => {
  599. fn(this);
  600. });
  601. });
  602. }
  603. isSlot(node) {
  604. if (node.tagName === 'SLOT')
  605. return true;
  606. return false;
  607. }
  608. compileSlotElement(slot) {
  609. if (!(this.$vm instanceof MVVMComponent))
  610. return;
  611. if (this.$slot.children.length === 0) {
  612. slot.parentNode.removeChild(slot);
  613. return;
  614. }
  615. this.slotCallback.push(c => {
  616. c.compileElement(this.$slot);
  617. slot.parentNode.replaceChild(this.$slot, slot);
  618. });
  619. }
  620. parseComponentTemplate(templateHTML) {
  621. let element = ElementUtility.parseHTML(templateHTML);
  622. const template = document.createElement('template');
  623. if (element.length) {
  624. if (element.length === 1) {
  625. if (element[0].tagName.toLowerCase() !== 'template')
  626. template.appendChild(element[0]);
  627. }
  628. else
  629. toArray(element).forEach((child) => {
  630. template.appendChild(child);
  631. });
  632. }
  633. return ElementUtility.fragment(template);
  634. }
  635. parseTemplate(leftString, rightString) {
  636. return (node, newValue, oldValue) => {
  637. const str = leftString + newValue + rightString;
  638. ElementUtility.text(node, str);
  639. };
  640. }
  641. compileElement(el) {
  642. let childNodes = [];
  643. // slice
  644. el.childNodes.forEach(node=>{
  645. childNodes.push(node)
  646. })
  647. childNodes.forEach((node) => {
  648. if (el['__for__'])
  649. node['__for__'] = el['__for__'];
  650. let reg = /\{\{(.*)\}\}/;
  651. if (ElementUtility.isElementNode(node)) {
  652. if (this.isComponent(node))
  653. this.compileComponent(node.tagName.toLowerCase(), node);
  654. else if (this.isSlot(node))
  655. this.compileSlotElement(node);
  656. else
  657. this.compile(node);
  658. }
  659. else if (ElementUtility.isTextNode(node) &&
  660. reg.test(node.textContent))
  661. bindWatcher(node, this.$vm, RegExp.$1.trim(), this.parseTemplate(RegExp.leftContext, RegExp.rightContext));
  662. if (node.childNodes && node.childNodes.length)
  663. this.compileElement(node);
  664. });
  665. }
  666. compile(node) {
  667. let nodeAttrs = node.attributes;
  668. toArray(nodeAttrs).forEach((attr) => {
  669. let attrName = attr.name;
  670. if (!isDirective(attrName)){
  671. if (attrName.startsWith('[') && attrName.endsWith(']')) {
  672. node.removeAttribute(attrName)
  673. let realAttrName = attrName.replace('[','')
  674. realAttrName = realAttrName.replace(']','')
  675. bindWatcher(node,this.$vm,attr.value,(node,newVal,oldVal)=>{
  676. node.setAttribute(realAttrName,newVal)
  677. })
  678. }
  679. return;
  680. }
  681. let dir = attrName.substring(2);
  682. let suffix = dir.split(':')[1];
  683. let exp = attr.value || suffix;
  684. if (isEventDirective(dir))
  685. eventHandler(node, this.$vm, exp, suffix);
  686. else if (isTextDirective(dir))
  687. bindWatcher(node, this.$vm, exp, ElementUtility.text);
  688. else if (isHtmlDirective(dir))
  689. bindWatcher(node, this.$vm, exp, ElementUtility.html);
  690. else if (isClassDirective(dir))
  691. bindWatcher(node, this.$vm, exp, ElementUtility.class);
  692. else if (isModelDirective(dir)) {
  693. bindWatcher(node, this.$vm, exp, ElementUtility.model);
  694. let val = getVMVal(this.$vm, exp);
  695. node.addEventListener('input', (e) => {
  696. let target = e.target;
  697. let newValue = target.value;
  698. if (val === newValue)
  699. return;
  700. setVMVal(this.$vm, exp, newValue);
  701. val = newValue;
  702. });
  703. }
  704. else if (isStyleDirective(dir))
  705. bindWatcher(node, this.$vm, exp, ElementUtility.style);
  706. else if (isShowDirective(dir))
  707. bindWatcher(node, this.$vm, exp, ElementUtility.display);
  708. else if (isRefDirective(dir))
  709. this.$vm.$refs[exp] = node;
  710. else if (isForDirective(dir))
  711. forHandler(node, this.$vm, exp, this);
  712. node.removeAttribute(attrName);
  713. });
  714. }
  715. isComponent(node) {
  716. const tagName = node.tagName.toLowerCase();
  717. if (!/^[(a-zA-Z)-]*$/.test(tagName))
  718. return false;
  719. if (this.$vm.components && hasOwn(this.$vm.components, tagName))
  720. return true;
  721. return false;
  722. }
  723. compileComponent(componentName, node) {
  724. const attributes = []
  725. toArray(node.attributes).forEach((attr) => {
  726. attributes.push(attr)
  727. })
  728. const componentOptions = this.$vm.components[componentName];
  729. const component = new MVVMComponent(extend(componentOptions, {
  730. parent: this.$vm
  731. }));
  732. component.$mount(node);
  733. this.$vm.$children[componentName] = component;
  734. attributes.forEach(attr=>{
  735. let attrName = attr.name;
  736. if (!isDirective(attrName))
  737. return;
  738. let dir = attrName.substring(2);
  739. let suffix = dir.split(':')[1];
  740. let exp = attr.value || suffix;
  741. if (isEventDirective(dir))
  742. eventHandler(component, this.$vm, exp, suffix);
  743. else if (isRefDirective(dir))
  744. this.$vm.$refs[exp] = component;
  745. })
  746. }
  747. }