Computed计算属性

523 阅读1分钟

computed

1. vue2写法

  computed: {
    rulerName: {
      get(): string {
        return this.name
      },
      set(value: string) {
        this.$emit("update:name", value)
      }
    }
  }

2. vue3写法

接受一个 getter 函数,并根据 getter 的返回值返回一个不可变的响应式 ref 对象。

const count = ref<number>(1)
const plusOne = computed(():number => count.value + 1)
console.log(plusOne.value) // 2
plusOne.value++ // 错误

或者,接受一个具有 get 和 set 函数的对象,用来创建可写的 ref 对象。

const count = ref<number>(1)
const plusOne = computed({
  get: ():number => count.value + 1,
  set: val:number => {
    count.value = val - 1
  }
})

plusOne.value = 1
console.log(count.value) // 0

3.使用场景一(处理style)

<script lang="tsx">
import type { CSSProperties, PropType } from "vue";
import { defineComponent, computed, unref } from "vue";

import { Tooltip } from "ant-design-vue";
import { InfoCircleOutlined } from "@ant-design/icons-vue";

import { getPopupContainer } from "/@/utils";
import { isString, isArray } from "/@/utils/is";
import { get } from "/@/utils/helper/tsxHelper";
import { propTypes } from "/@/utils/propTypes";

import { useDesign } from "/@/hooks/web/useDesign";

export default defineComponent({
  name: "BasicHelp",
  components: { Tooltip },
  props: {
    // max-width
    maxWidth: propTypes.string.def("600px"),
    // Whether to display the serial number
    showIndex: propTypes.bool,
    // color
    color: propTypes.string.def("#ffffff"),
    fontSize: propTypes.string.def("14px"),
    placement: propTypes.string.def("right"),
    absolute: propTypes.bool,
    // Text list
    text: {
      type: [Array, String] as PropType<string[] | string>,
    },
    // 定位
    position: {
      type: [Object] as PropType<any>,
      default: () => ({
        position: "absolute",
        left: 0,
        bottom: 0,
      }),
    },
  },
  setup(props, { slots }) {
    const { prefixCls } = useDesign("basic-help");
    const getOverlayStyle = computed(
      (): CSSProperties => {
        return {
          maxWidth: props.maxWidth,
        };
      }
    );
    const getWrapStyle = computed(
      (): CSSProperties => {
        return {
          color: props.color,
          fontSize: props.fontSize,
        };
      }
    );
    const getMainStyleRef = computed(() => {
      return props.absolute ? props.position : {};
    });
    const renderTitle = () => {
      const list = props.text;
      if (isString(list)) {
        return <p>{list}</p>;
      }
      if (isArray(list)) {
        return list.map((item, index) => {
          return (
            <p key={item}>
              <>
                {props.showIndex ? `${index + 1}. ` : ""}
                {item}
              </>
            </p>
          );
        });
      }
      return null;
    };
    return () => {
      return (
        <Tooltip/>
      );
    };
  },
});
</script>

4.使用场景二(处理props)

<template>
<span :class="getClass"><Icon icon="ion:chevron-forward" :style="$attrs.iconStyle"></Icon></span></template>
<script lang="ts">
import { defineComponent, computed } from "vue";
import { useDesign } from "/@/hooks/web/useDesign";
import { propTypes } from "/@/utils/propTypes";
import { Icon } from "/@/components/Icon";
export default defineComponent({
  name: "BasicArrow",
  components: { Icon },
  props: {
    expand: propTypes.bool,
    top: propTypes.bool,
    bottom: propTypes.bool,
    inset: propTypes.bool,
  },
  setup(props) {
    const { prefixCls } = useDesign("basic-arrow");
    const getClass = computed(() => {
      const { expand, top, bottom, inset } = props;
      return [
        prefixCls,
        {
          [`${prefixCls}--active`]: expand,
          top,
          inset,
          bottom,
        },
      ];
    });
    return {
      getClass,
    };
  },
});
</script>

5.使用场景三(组件v-model)

<template>
  <div class="create-rule">
    <div class="top">
      <a-form-item label="名称">
        <a-input
          v-model:value="rulerName"
          allowClear
          class="mr-4"
          :style="{ width: isAdd ? 'calc(100% - 150px)' : 'calc(100% - 220px)'}"
        />
        <a-checkbox v-model:checked="isSuit"></a-checkbox>
        <a-button v-if="!isAdd" type="primary" @click="reset"></a-button>
      </a-form-item>
    </div>
    <slot name="prerequisites"></slot>
    <slot name="condition-meet"></slot>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
  props: {
    name: { type: String, default: '' },
    checked: { type: Boolean, default: true },
    isAdd: { type: Boolean, default: true }
  },
  emits: ["update:checked", "update:name", 'reset'],
  computed: {
    rulerName: {
      get(): string {
        return this.name
      },
      set(value: string) {
        this.$emit("update:name", value)
      }
    },
    isSuit: {
      get(): boolean {
        return this.checked
      },
      set(value: boolean) {
        this.$emit("update:checked", value)
      }
    }
  },
  methods: {
    reset() {
      this.$emit('reset')
    }
  }
})
</script>