npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vue-dm

v1.0.5

Published

调整插件载入方式

Readme

vue-dm


vue3的数据管理模型,提供传统mvc模式的m层基类封装与设计

一、背景

  • vue、react等框架的产生,前端开发模式从事件驱动走入了数据驱动时代
  • vue3的出现使得vue的语法更加灵活、便于封装。已经脱离了vue2的 data、methods固化的结构设计。
  • vue3的灵活也带来了一些疑惑?vue3的组件该如何设计封装呢?vue3也加入了composition思想,但composition思想并没有明确的规范设计。导致我们在使用vue3的时候,对于组件的封装设计无从下手。
  • vue3的ref类导致数据操作与读取调用链变长,例如:data['value'][prop]
  • vue-dm为了解决以上问题而产生

二、vue-dm数据模型定义

  • 什么是数据模型?
    • 一组数据的所有操作方法与属性集合
  • 为什么要抽取数据模型?
    • 对某组数据的操作方法在所有业务逻辑上是通用的

三、API

  • Model装饰器: 所有基于vue-dm的创建的数据模型都必须使用Model装饰器
  • ChildModel装饰器:通过该装饰器可便捷的将子模型挂在到父模型
  • DataModel基类:vue-dm的核心实现,提供了data、getTemplateData、getData、onDataUpdate等属性、方法

四、DataModel提供的属性

| 参数 | 说明 | 类型 | 默认值 | | -- | -- | -- | -- | | data | 主数据(受保护属性,实例无法访问) | T | undefined |

五、DataModel提供的方法

| 参数 | 说明 | 参数 | 返回类型 | | -- | -- | -- | -- | | getData | 获取主数据 | (data: T) => void | T | | getTemplateData | 获取模版数据 | 无 | Ref |

六、示例

  • 订单地址模型
// addressList.ts
import { DataModel, Model } from 'vue-dm';

@Model
export default class AddressList extends DataModel<TypeOrder.AddressList[]> {
  public setName(name: string): void {
    this.data.forEach((item) => {
      item.name = name;
    });
  }
  public static filterAddressList(
    data: TypeOrder.AddressList[],
    list: string[]
  ): TypeOrder.AddressList[] {
    return data.filter((item) => list.indexOf(item.code) > -1);
  }
}
  • 订单表单模型
// orderFormData.ts
import { reactive } from 'vue';
import { Model, ChildModel, DataModel } from 'vue-dm';
import AddressList from './addressList';
/**
 * 订单表单模型
 */
@Model
export default class OrderFormData extends DataModel<TypeOrder.FormData> {
  /**
   * 地址模型
   */
  @ChildModel<TypeOrder.FormData>('address_list', AddressList)
  public addressListModel!: AddressList;
  /**
   * 初始化表单数据
   * @returns 初始化表单数据
   */
  protected __init(): TypeOrder.FormData {
    return reactive({
      code: '',
      name: '',
      id: 0,
      address_list: [
        { name: '测试', code: '1' },
        { name: '测试1', code: '2' },
      ],
    });
  }
  /** 初始化表单数据 */
  public initFormData() {
    this.data = this.__init();
  }
  /**
   * 通过详情数据生成表单数据
   * @param detailData
   * @returns
   */
  public setFormDataByDetail(detailData: any) {
    Object.assign(this.data, {
      code: detailData.code,
      name: detailData.name,
      id: detailData.id,
    });
  }
}
  • 页面组件
<template>
  <div class="home">
    <a-form ref="formDataRef">
      <a-form-item label="代码">
        <a-input v-model:value="formData.code" />
      </a-form-item>
      <a-form-item label="订单名称">
        <a-input v-model:value="formData.name" />
      </a-form-item>

      <a-button @click="handleSetData">设置数据</a-button>
      <div>
        <p v-for="item in formData.address_list" :key="item.code">
          {{ item.name }}
        </p>
      </div>
      <a-button
        type="primary"
        style="margin-left: 10px"
        :loading="loading"
        @click="handleSave"
        >保存</a-button
      >
      <a-button type="primary" style="margin-left: 10px" @click="handleAddress"
        >设置地址</a-button
      >
      <a-button type="primary" style="margin-left: 10px" @click="handleInitForm"
        >初始化表单数据</a-button
      >
    </a-form>
  </div>
</template>
<script lang="ts" setup>

import { ref } from 'vue';
import OrderFormData from '@/formData';
import OrderAddressList from '@/addressList';
import createLoading from '@/decorators/createLoading';

/**
 * 订单表单数据模型
 */
const orderFormData = new OrderFormData();
/**
 * 表单数据
 */
let formData = orderFormData.getTemplateData();
let data = orderFormData.getData((newData) => data = newData);

/**
 * 设置数据
 */
const handleSetData = () => {
  orderFormData.setFormDataByDetail({
    name: '测试订单',
    code: '123',
  });
};

/**
 * 请求方法
 */
const requestApi = (): Promise<void> => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve();
    }, 5000);
  });
};
/** 装饰器的使用 */
const { loading, fun: saveFun } = createLoading(requestApi);
/**
 * 静态方法调用
 */
console.log(
  OrderAddressList.filterAddressList(formData.value.address_list, ['1'])
);
/**
 * 保存数据
 */
const handleSave = () => {
  saveFun();
};
/**
 * 设置订单地址
 */
const handleAddress = () => {
  if (data.code === '123') {
    orderFormData.addressListModel.setName('地址');
  } else {
    console.log('无法删除订单');
  }
};

/**
 * 初始化订单数据
 */
const handleInitForm = () => orderFormData.initFormData();
</script>