瀏覽代碼

wip(vapor): custom directives

Evan You 1 年之前
父節點
當前提交
8549a243a5

+ 0 - 1
packages/compiler-vapor/src/generators/directive.ts

@@ -57,7 +57,6 @@ function genCustomDirectives(
 
 
   return [
   return [
     NEWLINE,
     NEWLINE,
-    // @ts-expect-error
     ...genCall(helper('withVaporDirectives'), element, directives),
     ...genCall(helper('withVaporDirectives'), element, directives),
   ]
   ]
 
 

+ 36 - 0
packages/runtime-vapor/src/directives/custom.ts

@@ -0,0 +1,36 @@
+import type { DirectiveModifiers } from '@vue/runtime-dom'
+import type { VaporComponentInstance } from '../component'
+import { renderEffect } from '../renderEffect'
+
+// !! vapor directive is different from vdom directives
+export type VaporDirective = (
+  node: Element | VaporComponentInstance,
+  value?: () => any,
+  argument?: string,
+  modifiers?: DirectiveModifiers,
+) => (() => void) | void
+
+type DirectiveArguments = Array<
+  | [VaporDirective | undefined]
+  | [VaporDirective | undefined, () => any]
+  | [VaporDirective | undefined, () => any, argument: string]
+  | [
+      VaporDirective | undefined,
+      value: () => any,
+      argument: string,
+      modifiers: DirectiveModifiers,
+    ]
+>
+
+export function withVaporDirectives(
+  node: Element | VaporComponentInstance,
+  dirs: DirectiveArguments,
+): void {
+  // TODO handle custom directive on component
+  for (const [dir, value, argument, modifiers] of dirs) {
+    if (dir) {
+      const ret = dir(node, value, argument, modifiers)
+      if (ret) renderEffect(ret)
+    }
+  }
+}

+ 13 - 4
packages/runtime-vapor/src/directives/vModel.ts

@@ -1,4 +1,5 @@
 import {
 import {
+  currentInstance,
   onMounted,
   onMounted,
   vModelCheckboxInit,
   vModelCheckboxInit,
   vModelCheckboxUpdate,
   vModelCheckboxUpdate,
@@ -26,12 +27,20 @@ type VaporModelDirective<
   modifiers?: { [key in Modifiers]?: true },
   modifiers?: { [key in Modifiers]?: true },
 ) => void
 ) => void
 
 
+function ensureMounted(cb: () => void) {
+  if (currentInstance!.isMounted) {
+    cb()
+  } else {
+    onMounted(cb)
+  }
+}
+
 export const applyTextModel: VaporModelDirective<
 export const applyTextModel: VaporModelDirective<
   HTMLInputElement | HTMLTextAreaElement,
   HTMLInputElement | HTMLTextAreaElement,
   'trim' | 'number' | 'lazy'
   'trim' | 'number' | 'lazy'
 > = (el, get, set, { trim, number, lazy } = {}) => {
 > = (el, get, set, { trim, number, lazy } = {}) => {
   vModelTextInit(el, trim, number, lazy, set)
   vModelTextInit(el, trim, number, lazy, set)
-  onMounted(() => {
+  ensureMounted(() => {
     let value: any
     let value: any
     renderEffect(() => {
     renderEffect(() => {
       vModelTextUpdate(el, value, (value = get()), trim, number, lazy)
       vModelTextUpdate(el, value, (value = get()), trim, number, lazy)
@@ -45,7 +54,7 @@ export const applyCheckboxModel: VaporModelDirective<HTMLInputElement> = (
   set,
   set,
 ) => {
 ) => {
   vModelCheckboxInit(el, set)
   vModelCheckboxInit(el, set)
-  onMounted(() => {
+  ensureMounted(() => {
     let value: any
     let value: any
     renderEffect(() => {
     renderEffect(() => {
       vModelCheckboxUpdate(
       vModelCheckboxUpdate(
@@ -64,7 +73,7 @@ export const applyRadioModel: VaporModelDirective<HTMLInputElement> = (
   set,
   set,
 ) => {
 ) => {
   addEventListener(el, 'change', () => set(vModelGetValue(el)))
   addEventListener(el, 'change', () => set(vModelGetValue(el)))
-  onMounted(() => {
+  ensureMounted(() => {
     let value: any
     let value: any
     renderEffect(() => {
     renderEffect(() => {
       if (value !== (value = get())) {
       if (value !== (value = get())) {
@@ -79,7 +88,7 @@ export const applySelectModel: VaporModelDirective<
   'number'
   'number'
 > = (el, get, set, modifiers) => {
 > = (el, get, set, modifiers) => {
   vModelSelectInit(el, get(), modifiers && modifiers.number, set)
   vModelSelectInit(el, get(), modifiers && modifiers.number, set)
-  onMounted(() => {
+  ensureMounted(() => {
     renderEffect(() => vModelSetSelected(el, traverse(get())))
     renderEffect(() => vModelSetSelected(el, traverse(get())))
   })
   })
 }
 }

+ 2 - 0
packages/runtime-vapor/src/index.ts

@@ -2,6 +2,7 @@
 export { createVaporApp } from './apiCreateApp'
 export { createVaporApp } from './apiCreateApp'
 export { defineVaporComponent } from './apiDefineComponent'
 export { defineVaporComponent } from './apiDefineComponent'
 export { vaporInteropPlugin } from './vdomInterop'
 export { vaporInteropPlugin } from './vdomInterop'
+export type { VaporDirective } from './directives/custom'
 
 
 // compiler-use only
 // compiler-use only
 export { insert, prepend, remove } from './block'
 export { insert, prepend, remove } from './block'
@@ -39,3 +40,4 @@ export {
   applySelectModel,
   applySelectModel,
   applyDynamicModel,
   applyDynamicModel,
 } from './directives/vModel'
 } from './directives/vModel'
+export { withVaporDirectives } from './directives/custom'