如何在Vue3 typescript中读取父属性

qybjjes1  于 2023-06-24  发布在  Vue.js
关注(0)|答案(1)|浏览(194)

在我尝试编写的子组件中,我需要获取父对象。注解掉的行不起作用。
AccordionState是:

export type AccordionKeys = | "open" | "disabled";

export type AccordionState = {
    [key: string]: {[key in AccordionKeys]: boolean; };
}

子代码为:

<script lang="ts">
    import { AccordionState } from "@/types/global";
    import { defineComponent, useAttrs } from "vue";

    export default defineComponent({
      name: "AccordionPane",
      props: {
        panelName: {
          type: String,
          required: true,
        },
      },
      computed: {
        open(): boolean {
          // const attrs = useAttrs();
          // const state = attrs.state as AccordionState;
          // return state[this.panelName].open && !state[this.panelName].disabled;
          return true;
        },
    disabled(): boolean {
      // const attrs = useAttrs();
      // const state = attrs.state as AccordionState;
      // return state[this.panelName].disabled;

      return false;
    },

**父组件。**这里计算的getProps显示我正确定义了prop.state,但AccordionPane中的注解代码不起作用。变量“state”为空。我在网上没有看到很多typescript的例子,而且JavaScript的例子是如此的非结构化,我不知道如何使它们适应typescript。

<template>
    <div class="accordionControl">
      <slot ref="content"></slot>
    </div>
    <textarea class="debug" v-model="getProps"></textarea>
  </template>

  <script lang="ts">

  import { type AccordionState } from '@/types/global';
  import { defineComponent, type PropType } from 'vue';

  export default defineComponent({
    name: "AccordionControl",
    props: {
      state: {
        type: Object as PropType<AccordionState>,
        required: true,
      },
      isVert: {
        type: Boolean,
        default: false,
      },
      allOpen: {
        type: Boolean,
        default: false,
      }
    },
    computed: {
      getProps(): string {
        return JSON.stringify(this.$props, null, '  ');
      }
    }
  });
  </script>

下面的链接是一个JavaScript示例,它可以工作。
https://play.vuejs.org/#eNp1kDFrwzAQhf/K9RY5YGTaMbUL2ToWOnSoOtjxORhkSUhyl5D/3pMVXCcQ0KDHvfse9854cE7+zoR7rMPRjy5CoDi7N2XGyVkf4QyeBrjA4O0Egq1CGWWO1oQIUzhBk+aFeCetLXy1oc/Pet0/id2K+dRjTz5TFMoq6xSt8DUR6yrnczKLSJPTbSRWAPV1uWsUviiEfcufZ/7k6ZXFoq7WPSzxPyJdtyFKKW+8S+Kj63saRkMf3rpQwhzoEKMPd31oiuCSg9vY+Itv0YmfHZ+XDO2y2KyMgstJNVpNUttTsQBkV2ajbHm86QQvf3ztlVg=

n6lpvg4x

n6lpvg4x1#

我最终使用了一个服务。

import type { 
    AccordionChildMap,
    AccordionStates,
    AccordionData,
    AccordionProps,
    AccordionKeys,
    AccordionAction,
    AccordionPanelState,
  } from '@/types/global';

  class AccordionServiceInstance {
    #childMap: AccordionChildMap;
    #datas: AccordionStates;
    #props: { [key: string] : AccordionProps };
    #actionHandlers: { [key: string] : AccordionAction }
    #nameIndex: number;
    
    constructor() {
      this.#childMap = {};
      this.#datas = {};
      this.#props = {};
      this.#nameIndex = 0;
      this.#actionHandlers = {};
    }

    registerParent(data: AccordionData, isVert: boolean, allOpen: boolean) : string {
      console.log("ParentHeight: " + data.height);
      const parentName = "accordion" + this.#nameIndex++;
      this.#props[parentName] = {
        isVert: isVert,
        allOpen: allOpen,
      } 
      this.#datas[parentName] = data;
      return parentName;
    }

    registerChild(childName: string, onChange: AccordionAction, headerHeight: number) : string {
      
      let foundParent = "";
      console.log("set headerHeight: " + headerHeight);
      
      const keys = Object.keys(this.#datas)
      for (let i=0; i < keys.length && foundParent == ""; i++) {
        const key = keys[i];
        const parentKeys = Object.keys(this.#datas[key].state);
        if (parentKeys.indexOf(childName) > -1) {
          foundParent = key;
          this.#childMap[childName] = key;
          this.#actionHandlers[childName] = onChange;
          this.#datas[foundParent].headerHeight = headerHeight;
        } else {
          console.log("AccordionService could not find parent for: " + childName);
        }
      }
      return foundParent;
    }

    getPanelHeight(childName: string) : string {
      const stateName = this.#childMap[childName];
      const data = this.#datas[stateName]
      const state = data.state;
      const props = this.#props[stateName];
      const childState = state[childName];
      const childCount = Object.keys(state).length;
      return (childState.disabled || 
        !childState.open) ? "0" :
          props.allOpen ? "auto" : (data.height - childCount * (data.headerHeight + 8) + "px");
    }

    getChildState(childName: string) : AccordionPanelState {
      const stateName = this.#childMap[childName];
      return this.#datas[stateName].state[childName];
    }

    getChildProps(childName: string) : AccordionProps {
      const stateName = this.#childMap[childName];
      return this.#props[stateName];
    }

    getData(parentName: string) : AccordionData {
      return this.#datas[parentName];
    }

    setHeight(parentName: string, height: number) : void {
      console.log("set height: " + height);
      this.#datas[parentName].height = height;
      const state = this.#datas[parentName].state;

      Object.keys(state).forEach( (x) => {
        console.log(x + "| open:" + state[x].open + "| disabled:" + state[x].disabled)
        this.#actionHandlers[x](state[x].open, state[x].disabled);
      });
    }

    changeChildState(childName : string, property: AccordionKeys, value: boolean) : void {
      const stateName = this.#childMap[childName];
      const props = this.#props[stateName];
      const state = this.#datas[stateName].state;
      if (!props.allOpen && property == "open" && value) {
        Object.keys(state).forEach( (x) => {
          if (x == childName) {
            state[x].open = true;
          } else {
            state[x].open = false;
          }
        });
      } else {
        state[childName].open = value;
      }
      Object.keys(state).forEach( (x) => {
        console.log(x + "| open:" + state[x].open + "| disabled:" + state[x].disabled)
        this.#actionHandlers[x](state[x].open, state[x].disabled);
      });
    }
  }

  export const AccordionService = new AccordionServiceInstance();

使用控件:

<AccordionControl :state="{
    colorWheel: { open: true, disabled: false },
    colorMixer: { open: false, disabled: false },
    colorSelector: { open: false, disabled: true },
  }"
 >
   <AccordionPane panelName="colorWheel">
      <template v-slot:header>
        <h2>Create Color Scheme</h2>
      </template>
      <template v-slot:content>
        Stuff here
      </template>
    </AccordionPane>
    <AccordionPane panelName="colorMixer">
      <template v-slot:header>
        <h2>Color Mixer</h2>
      </template>
      <template v-slot:content>
        <h1>Stuff here</h1>
      </template>
    </AccordionPane>
    <AccordionPane panelName="colorSelector">
      <template v-slot:header>
        <h2>Assign / Select colors</h2>
      </template>
      <template v-slot:content>
        <h1>Stuff here</h1>
      </template>
    </AccordionPane>
  </AccordionControl>

在答案中还有很多需要解释的,比如样式表和控件,所以我希望你能看到:
编辑:新的公共链接,你应该可以看到这个。
https://codesandbox.io/p/github/geewhizbang/iconBuilder/main?layout=%257B%2522sidebarPanel%2522%253A%2522EXPLORER%2522%252C%2522rootPanelGroup%2522%253A%257B%2522direction%2522%253A%2522horizontal%2522%252C%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522id%2522%253A%2522ROOT_LAYOUT%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522EDITOR%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522panelType%2522%253A%2522TABS%2522%252C%2522id%2522%253A%2522clj0o2kvv000b356mxs0qrg76%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522DEVTOOLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522panelType%2522%253A%2522TABS%2522%252C%2522id%2522%253A%2522clj0o2kvv000d356m2n227iv8%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%252C%2522sizes%2522%253A%255B50%252C50%255D%257D%252C%2522tabbedPanels%2522%253A%257B%2522clj0o2kvv000b356mxs0qrg76%2522%253A%257B%2522id%2522%253A%2522clj0o2kvv000b356mxs0qrg76%2522%252C%2522activeTabId%2522%253A%2522clj1st09l00no356mzhtu2p2h%2522%252C%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clj0o2kvv000a356m5qfapa5a%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252FREADME.md%2522%252C%2522state%2522%253A%2522IDLE%2522%257D%252C%257B%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252Fsrc%252Frouter%252Findex.ts%2522%252C%2522id%2522%253A%2522clj0o6qyd00dz356m24q2e1x1%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522state%2522%253A%2522IDLE%2522%257D%252C%257B%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252F.codesandbox%252Ftasks.json%2522%252C%2522id%2522%253A%2522clj1st09l00no356mzhtu2p2h%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%255D%257D%252C%2522clj0o2kvv000d356m2n227iv8%2522%253A%257B%2522id%2522%253A%2522clj0o2kvv000d356m2n227iv8%2522%252C%2522tabs%2522%253A%255B%257B%2522type%2522%253A%2522TASK_LOG%2522%252C%2522taskId%2522%253A%2522dev%2522%252C%2522id%2522%253A%2522clj0o2y5w006l356mlvlq3t5h%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%252C%257B%2522type%2522%253A%2522TASK_PORT%2522%252C%2522taskId%2522%253A%2522dev%2522%252C%2522port%2522%253A5173%252C%2522id%2522%253A%2522clj0o2zf800bt356mgg70yn0j%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522path%2522%253A%2522%252F%2522%257D%255D%252C%2522activeTabId%2522%253A%2522clj0o2zf800bt356mgg70yn0j%2522%257D%257D%252C%2522showDevtools%2522%253Atrue%252C%2522showSidebar%2522%253Atrue%252C%2522sidebarPanelSize%2522%253A15%257D
我希望这不是一个黑客。

相关问题