Vue3+TS combined with ant design to realize simple list page and detail page

When I was working on a project recently, because I had more contact with the list page and the details page, the list page is mainly similar to a table to display all the data, and the details page mainly refers to the detailed information of a certain piece of data, including modification, Creating a new piece of data, viewing, etc. are all corresponding to the details page, so this time I mainly want to do a small share about the implementation of the list page and the details page. The technology stack used is Vue3+Ts, and the component library used is ant design and tailwindcss. The specific implementation page can be seen in the figure below.

This page is a list page, which mainly displays the basic data of the user. After checking a piece of data, you can click to view it, and click delete to delete the current data.

 After clicking the new data button, you will enter the new data details page, which is a form. After the user enters the information and submits the verification, a new data will be added on the list page.

After selecting a piece of data on the list page, click View to jump to the details page of the piece of data, which displays all the information of the piece of data.

 

 

 Click the Modify button on the details page to modify the current data. After the modification is complete, click Submit to change the information of the current data.

Overall it is very simple, just two pages, a list page and a details page. Let's talk about the specific implementation ideas:

        In an actual project, all data is obtained from the backend, so all changes made will be sent to the backend through the interface request, and then the data is requested again to refresh the page. Here I made some fake data and assigned it when the page was initialized. When switching between the list page and the details page, I routed all the data as parameters, so I don’t have to worry about data loss caused by refreshing the page. .

Since the new page, the view details page, and the edit page all correspond to the same page, considering the reusability of components, the form is combined with v-if for control.

const routes = [
  {
    path: "/",
    component: () => import("../ant-table/Table.vue"),
  },
  {
    path: "/details",
    name: "details",
    component: () => import("../view/Detail.vue"),
  },
]

 The routing configuration is as shown in the figure, and the list page is entered by default.

Let's officially start writing the page:

<template>
  <div>
    <router-view></router-view>
  </div>
</template>

<script setup lang="ts"></script>

Here is the App root component, which is used to render the content when the route is switched.

interface DataType {
  name: string;
  age: string;
  address: any;
  sex: string;
  school: string;
  hobby: any;
  birthday: any;
  phone: string;
  description: string;
  position: {
    isShow: boolean;
    place: string;
  };
}

Define data types to facilitate type detection and writing specifications.

    <a-table
      :row-selection="{
        type: 'radio',
        selectedRowKeys: rowSelection.selectedRowKeys,
        onChange: onSelectChange,
      }"
      rowKey="name"
      :columns="columns"
      :data-source="data"
    >
      <template #bodyCell="{ column, record, text, index }">
        <template v-if="column.dataIndex === 'operation'">
          <span class="text-yn-400">
            <delete-two-tone @click="deleteData(record, index)" />
          </span>
        </template>
        <template v-if="column.dataIndex === 'index'">
          <span>
            {
   
   { index }}
          </span>
        </template>
        <template v-if="column.dataIndex === 'address'">
          <span v-for="city in record.address">
            {
   
   { city }}
          </span>
        </template>
        <template v-if="column.dataIndex === 'hobby'">
          <span
            v-for="hobby in record.hobby"
            class="bg-green-200 rounded-lg py-1 px-1.5 mx-1.5"
          >
            {
   
   { hobby }}
          </span>
        </template>
      </template>
    </a-table>

This part of the code is mainly to define some data, including the header of the table, initialize the table data, etc.

// 跳转详情页
const toDetails = () => {
  if (rowSelection.selectedRowKeys.length !== 1) {
    message.error("请选择一条数据!");
  } else {
    let selectName = rowSelection.selectedRowKeys[0];
    let usedata: any = toRaw(data.value);
    router.push({
      path: "/details",
      query: { selectName, useData: JSON.stringify(usedata) },
    });
  }
};

 Jump to the code to view the details page as shown in the figure: the query parameter here is passed the name of the currently selected data (as a unique identifier), and also passed all the data on the list page, pay attention to the routing parameter here, if passed It is non-string type data, which needs to be wrapped with JSON.stringify and parsed with JSON.parse when receiving.

// 新建记录
const addNewData = () => {
  let usedata: any = toRaw(data.value);
  router.push({
    path: "/details",
    query: {
      useData: JSON.stringify(usedata),
    },
  });
};

Here is the corresponding code when you click to create new data.

 This part of the code is the code corresponding to the operation of initializing the page and deleting the list data. I made a judgment on initializing the data here, that is, whether there is any data when the page is loaded. If there is no data, I will use the few pieces of data defined at the beginning. If If there is data (from the details page), use the data on the details page. The beauty here is that in fact, only when the page is loaded, there is no data, and the default data will be used, and there will be data every time the page route is switched afterwards.

      <a-form
        :model="baseForm"
        name="basic"
        class="grid grid-cols-3"
        ref="formRef"
        :rules="baseInfoEules"
        layout="vertical"
      >
        <!-- 姓名 -->
        <div class="col-span-1 mx-3">
          <a-form-item name="name" label="姓名">
            <span v-if="!isEdit">{
   
   { baseForm.name }}</span>
            <a-input
              :disabled="disableName"
              v-else
              v-model:value="baseForm.name"
            />
          </a-form-item>
        </div>
        <!-- 年龄 -->
        <div class="col-span-1 mx-3">
          <a-form-item name="age" label="年龄">
            <span v-if="!isEdit">{
   
   { baseForm.age }}</span>
            <a-input-number
              class="w-full"
              id="inputNumber"
              v-else
              v-model:value="baseForm.age"
              :min="1"
              :max="99"
            />
          </a-form-item>
        </div>
        <!-- 性别 -->
        <div class="col-span-1 mx-3">
          <a-form-item name="sex" label="性别">
            <span v-if="!isEdit">{
   
   { baseForm.sex }}</span>
            <a-select
              v-else
              v-model:value="baseForm.sex"
              placeholder="Please select sex"
            >
              <a-select-option value="男">男</a-select-option>
              <a-select-option value="女">女</a-select-option>
            </a-select>
          </a-form-item>
        </div>
        <!-- 地址 -->
        <div class="col-span-1 mx-3">
          <a-form-item name="address" label="地址">
            <span v-if="!isEdit" v-for="city in baseForm.address">{
   
   {
              city
            }}</span>
            <a-cascader
              v-else
              v-model:value="baseForm.address"
              :options="cityOptions"
              placeholder="Please select address"
            />
          </a-form-item>
        </div>
        <!-- 学校 -->
        <div class="col-span-1 mx-3">
          <a-form-item name="school" label="学校">
            <span v-if="!isEdit">{
   
   { baseForm.school }}</span>
            <a-select
              v-else
              v-model:value="baseForm.school"
              placeholder="Please select a university"
            >
              <a-select-option value="西南大学">西南大学</a-select-option>
              <a-select-option value="中南大学">中南大学</a-select-option>
              <a-select-option value="武汉大学">武汉大学</a-select-option>
              <a-select-option value="浙江大学">浙江大学</a-select-option>
            </a-select>
          </a-form-item>
        </div>
        <!-- 爱好 -->
        <div class="col-span-1 mx-3">
          <a-form-item name="hobby" label="爱好">
            <span
              v-if="!isEdit"
              v-for="hobby in baseForm.hobby"
              class="mr-1.5 bg-green-200 py-1 px-1.5 pb-1.5 rounded-lg"
              >{
   
   { hobby }}</span
            >
            <a-select
              :options="options"
              :fieldNames="{ label: 'label', value: 'value' }"
              v-else
              v-model:value="baseForm.hobby"
              mode="multiple"
              placeholder="Please select hobby"
            >
            </a-select>
          </a-form-item>
        </div>
        <!-- 出生日期 -->
        <div class="col-span-1 mx-3">
          <a-form-item name="birthday" label="出生日期">
            <span v-if="!isEdit">{
   
   { baseForm.birthday }}</span>
            <a-date-picker
              placeholder="请选择时间"
              style="width: 100%"
              v-else
              v-model:value="baseForm.birthday"
              value-format="YYYY-MM-DD"
            />
          </a-form-item>
        </div>
        <!-- 手机号 -->
        <div class="col-span-1 mx-3">
          <a-form-item name="phone" label="手机号码">
            <span v-if="!isEdit">{
   
   { baseForm.phone }}</span>
            <a-input
              v-else
              v-model:value="baseForm.phone"
              placeholder="请输入手机号码"
            />
          </a-form-item>
        </div>
        <!-- 位置信息 -->
        <a-form-item name="position" label="">
          <div class="col-span-1 mx-3 pt-8">
            <span class="mx-3">是否显示位置信息</span>
            <a-switch v-model:checked="baseForm.position!.isShow" />
            <span
              class="mx-3 bg-blue-200 px-1.5 py-1 rounded-md"
              v-if="baseForm.position!.isShow"
              >{
   
   { baseForm.position?.place }}
            </span>
          </div>
        </a-form-item>
        <!-- 说明 -->
        <div class="col-span-3 mx-3">
          <a-form-item name="description" label="情况说明">
            <span v-if="!isEdit">{
   
   { baseForm.description }}</span>
            <a-textarea
              v-else
              :rows="4"
              v-model:value="baseForm.description"
              placeholder="请输入说明"
            >
            </a-textarea>
          </a-form-item>
        </div>
      </a-form>

The form content of the details page is as follows. Use v-if to judge whether it is currently in an editable form or an information viewing state.

// 获取列表页数据
if (route.query.useData as any) {
  useData.value = JSON.parse(route.query.useData as any) || [];
  dataSource.value = useData.value;
}

 Get the data passed by the list page

 This part of the code will not be shown, and you should be able to know what I am doing by looking at the comments on the picture.

// 初始化数据
const initData = () => {
  dataSource.value = useData.value;
  // 表单置空
  getEmptydata();
  // 是否查看详情页
  if (receiveName) {
    dataSource.value.map((item) => {
      if (item.name === receiveName) {
        editData = item;
        baseForm.value.name = item.name;
        baseForm.value.age = item.age;
        baseForm.value.sex = item.sex;
        baseForm.value.school = item.school;
        baseForm.value.address = item.address;
        baseForm.value.hobby = item.hobby;
        baseForm.value.phone = item.phone;
        baseForm.value.birthday = item.birthday;
        baseForm.value.description = item.description;
        baseForm.value.position = item.position || {
          isShow: false,
          place: "湖北  武汉",
        };
      }
    });
  } else {
    // 新增数据页面
    isEdit.value = true;
    disableName.value = false;
  }
};
onMounted(() => {
  initData();
});

This part of the code is more critical, that is, when initializing the details page, first judge whether it is a new page or a viewing page by passing parameters. In the list page, if you click to view the details, the name value of the selected data is passed, and There is no transmission when you click Create, here is to determine whether to create new data or view details by judging whether the name value of the routing parameter has been received.

// 提交
const submit = () => {
  // 修改后提交
  if (receiveName) {
    formRef.value?.validateFields().then(
      (res) => {
        isEdit.value = !isEdit.value;
        let newData: any = res;
        dataSource.value.map((item) => {
          // 把修改的数据替换掉原来的数据
          if (item.name == receiveName) {
            item.name = newData?.name;
            item.age = newData?.age;
            item.sex = newData?.sex;
            item.school = newData?.school;
            item.address = newData?.address;
            item.hobby = toRaw(newData?.hobby);
            item.birthday = newData?.birthday;
            item.phone = newData?.phone;
            item.position = newData.position;
            item.description = newData?.description;
          }
        });
        router.push({
          path: "/",
          query: { obj: JSON.stringify(dataSource.value) },
        });
      },
      (error) => {
        console.log(error);
      }
    );
  } else {
    // 新增后提交
    formRef.value?.validateFields().then(
      (res) => {
        console.log(res);
        if (res) {
          isEdit.value = !isEdit.value;
          let newData: any = res;
          dataSource.value.push(newData);
          router.push({
            path: "/",
            query: { obj: JSON.stringify(dataSource.value) },
          });
        }
      },
      (error) => {
        console.log(error);
      }
    );
  }
};

This part of the code is also very important, which is the method triggered by clicking submit after modification or addition.

First judge whether to modify or create new data, and then submit the form to get the process. If it is a modified submission, replace the original data with the modified data. If it is new data, then push it directly into the data. Finally, after the modification is completed, the route jumps to the list page, and all the data is passed as a reference.

So far, a simple list page and details page have been realized. Some parts do have relatively high redundancy and can be further optimized and improved, and some details can also be optimized, such as regular matching of mobile phone numbers.

Sure enough, it is still easier to adjust the interface and request data directly from the backend haha, otherwise it would be too troublesome to get so much data every time.

There are other questions welcome to criticize and correct!

I will put the source code in the code cloud warehouse later

Guess you like

Origin blog.csdn.net/weixin_48914380/article/details/128904901