基于 Vue 3 + Element Plus + ECharts + JavaScript 开发“大学生志愿者服务”项目

本文将详细介绍使用 Vue 3Element PlusEChartsJavaScript 开发“大学生志愿者服务”项目的具体语法知识点及其使用方法。每个知识点将包含详细的案例代码,并附有详细注释。最后,将提供一些综合性案例,帮助您更好地理解和应用所学知识。


一、项目分析

1. 项目需求分析

  • 用户角色:大学生志愿者
  • 主要功能
    • 首页:展示项目概览、最新活动等
    • 个人信息维护:用户可以查看和编辑个人信息
    • 积分排名:展示志愿者的积分排名情况
    • 活动列表:显示所有可报名或已报名的活动
    • 活动详情:展示活动的详细信息
    • 我的报名:用户查看和管理自己的报名信息
    • 服务记录上传:用户上传服务记录
    • 服务记录列表:展示用户的服务记录
    • 服务记录详情:展示单条服务记录的详细信息

2. 技术选型

  • 前端框架:Vue 3
  • UI 组件库:Element Plus
  • 数据可视化:ECharts
  • 状态管理:Vuex 或 Pinia(可选)
  • 路由管理:Vue Router
  • HTTP 客户端:Axios
  • Mock 数据:Mock.js

二、项目展示

在项目开发过程中,可以通过以下方式展示功能:

  • 组件化开发:将每个功能模块拆分为独立的组件,提高代码可维护性。
  • 路由配置:使用 Vue Router 配置页面路由,实现单页面应用(SPA)。
  • 状态管理:使用 Vuex 或 Pinia 管理全局状态,如用户信息、积分等。
  • 数据可视化:使用 ECharts 展示积分排名、服务记录统计等图表。

三、技术方案

1. 工程化项目搭建

a. 创建项目

使用 Vue CLI 创建 Vue 3 项目,并集成 Element Plus 和 ECharts。

# 安装 Vue CLI(如果尚未安装)
npm install -g @vue/cli

# 创建项目
vue create volunteer-project

# 进入项目目录
cd volunteer-project

# 安装 Element Plus 和 ECharts
npm install element-plus echarts
b. 配置项目

main.js 中引入 Element Plus 和 ECharts:

// main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import * as echarts from 'echarts';

const app = createApp(App);

// 挂载 Element Plus
app.use(ElementPlus);

// 挂载路由
app.use(router);

// 将 ECharts 挂载到全局属性
app.config.globalProperties.$echarts = echarts;

app.mount('#app');

2. 创建项目目录

volunteer-project/
├── public/
│   └── index.html
├── src/
│   ├── assets/
│   ├── components/
│   │   ├── Home.vue
│   │   ├── PersonalInfo.vue
│   │   ├── ScoreRanking.vue
│   │   ├── ActivityList.vue
│   │   ├── ActivityDetail.vue
│   │   ├── MyRegistration.vue
│   │   ├── ServiceRecordUpload.vue
│   │   ├── ServiceRecordList.vue
│   │   └── ServiceRecordDetail.vue
│   ├── router/
│   │   └── index.js
│   ├── store/
│   │   └── index.js
│   ├── views/
│   │   ├── HomeView.vue
│   │   ├── PersonalInfoView.vue
│   │   ├── ScoreRankingView.vue
│   │   ├── ActivityListView.vue
│   │   ├── ActivityDetailView.vue
│   │   ├── MyRegistrationView.vue
│   │   ├── ServiceRecordUploadView.vue
│   │   ├── ServiceRecordListView.vue
│   │   └── ServiceRecordDetailView.vue
│   ├── App.vue
│   └── main.js
├── package.json
└── ...其他配置文件

3. 资源准备

  • 图标和图片:将所需的图标和图片放入 src/assets/ 目录。
  • 样式文件:在 src/assets/css/ 目录下编写全局样式或组件样式。

4. Mock 数据

使用 Mock.js 来模拟 API 接口数据。

a. 安装 Mock.js
npm install mockjs
b. 创建 Mock 文件

src/mock/ 目录下创建 index.js

// src/mock/index.js
import Mock from 'mockjs';

Mock.mock('/api/user/info', {
  'name': '张三',
  'age': 20,
  'email': 'zhangsan@example.com',
  'points': 150,
  'ranking': 3
});

Mock.mock('/api/activities', {
  'activities|10': [
    {
      'id|+1': 1,
      'title': '@title',
      'date': '@date',
      'location': '@city',
      'description': '@paragraph'
    }
  ]
});

// 其他 Mock 数据...
c. 引入 Mock

main.js 中引入 Mock:

// main.js
import './mock';

四、项目功能开发

1. 页面入口

a. 配置路由

src/router/index.js 中配置路由:

// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import HomeView from '../views/HomeView.vue';
import PersonalInfoView from '../views/PersonalInfoView.vue';
import ScoreRankingView from '../views/ScoreRankingView.vue';
import ActivityListView from '../views/ActivityListView.vue';
import ActivityDetailView from '../views/ActivityDetailView.vue';
import MyRegistrationView from '../views/MyRegistrationView.vue';
import ServiceRecordUploadView from '../views/ServiceRecordUploadView.vue';
import ServiceRecordListView from '../views/ServiceRecordListView.vue';
import ServiceRecordDetailView from '../views/ServiceRecordDetailView.vue';

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/personal-info',
    name: 'personal-info',
    component: PersonalInfoView
  },
  {
    path: '/score-ranking',
    name: 'score-ranking',
    component: ScoreRankingView
  },
  {
    path: '/activities',
    name: 'activities',
    component: ActivityListView
  },
  {
    path: '/activities/:id',
    name: 'activity-detail',
    component: ActivityDetailView,
    props: true
  },
  {
    path: '/my-registration',
    name: 'my-registration',
    component: MyRegistrationView
  },
  {
    path: '/service-record-upload',
    name: 'service-record-upload',
    component: ServiceRecordUploadView
  },
  {
    path: '/service-records',
    name: 'service-records',
    component: ServiceRecordListView
  },
  {
    path: '/service-records/:id',
    name: 'service-record-detail',
    component: ServiceRecordDetailView,
    props: true
  }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

export default router;

2. 首页

a. HomeView.vue
<!-- src/views/HomeView.vue -->
<template>
  <el-container>
    <el-header>
      <h2>大学生志愿者服务首页</h2>
    </el-header>
    <el-main>
      <el-card>
        <h3>最新活动</h3>
        <el-table :data="latestActivities" style="width: 100%">
          <el-table-column prop="title" label="活动名称" />
          <el-table-column prop="date" label="活动时间" />
          <el-table-column prop="location" label="活动地点" />
          <el-table-column label="操作">
            <template #default="scope">
              <el-button type="primary" @click="goToDetail(scope.row.id)">查看详情</el-button>
            </template>
          </el-table-column>
        </el-table>
      </el-card>
    </el-main>
  </el-container>
</template>

<script>
export default {
  name: 'HomeView',
  data() {
    return {
      latestActivities: []
    };
  },
  methods: {
    fetchLatestActivities() {
      // 模拟 API 请求
      this.latestActivities = [
        {
          id: 1,
          title: '社区清洁活动',
          date: '2023-10-15',
          location: '昆明市'
        },
        {
          id: 2,
          title: '敬老院志愿服务',
          date: '2023-10-20',
          location: '大理市'
        }
      ];
    },
    goToDetail(id) {
      this.$router.push({ name: 'activity-detail', params: { id } });
    }
  },
  mounted() {
    this.fetchLatestActivities();
  }
};
</script>

<style scoped>
.el-header {
  background-color: #409EFF;
  color: white;
  text-align: center;
  line-height: 60px;
}
.el-main {
  padding: 20px;
}
</style>

3. 个人信息维护

a. PersonalInfoView.vue
<!-- src/views/PersonalInfoView.vue -->
<template>
  <el-container>
    <el-header>
      <h2>个人信息维护</h2>
    </el-header>
    <el-main>
      <el-form :model="userInfo" label-width="120px">
        <el-form-item label="姓名">
          <el-input v-model="userInfo.name" />
        </el-form-item>
        <el-form-item label="年龄">
          <el-input v-model.number="userInfo.age" />
        </el-form-item>
        <el-form-item label="邮箱">
          <el-input v-model="userInfo.email" />
        </el-form-item>
        <el-form-item label="积分">
          <el-input v-model="userInfo.points" disabled />
        </el-form-item>
        <el-form-item label="排名">
          <el-input v-model="userInfo.ranking" disabled />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="saveInfo">保存</el-button>
        </el-form-item>
      </el-form>
    </el-main>
  </el-container>
</template>

<script>
export default {
  name: 'PersonalInfoView',
  data() {
    return {
      userInfo: {
        name: '',
        age: 0,
        email: '',
        points: 0,
        ranking: 0
      }
    };
  },
  methods: {
    fetchUserInfo() {
      // 模拟 API 请求
      this.userInfo = {
        name: '张三',
        age: 20,
        email: 'zhangsan@example.com',
        points: 150,
        ranking: 3
      };
    },
    saveInfo() {
      // 模拟保存逻辑
      this.$message({
        message: '保存成功',
        type: 'success'
      });
    }
  },
  mounted() {
    this.fetchUserInfo();
  }
};
</script>

<style scoped>
.el-header {
  background-color: #409EFF;
  color: white;
  text-align: center;
  line-height: 60px;
}
.el-main {
  padding: 20px;
}
</style>

4. 积分排名

a. ScoreRankingView.vue
<!-- src/views/ScoreRankingView.vue -->
<template>
  <el-container>
    <el-header>
      <h2>积分排名</h2>
    </el-header>
    <el-main>
      <el-table :data="rankingData" style="width: 100%">
        <el-table-column prop="name" label="姓名" />
        <el-table-column prop="points" label="积分" />
        <el-table-column prop="ranking" label="排名" />
      </el-table>
      <el-card>
        <div ref="chart" style="width: 100%; height: 400px;"></div>
      </el-card>
    </el-main>
  </el-container>
</template>

<script>
export default {
  name: 'ScoreRankingView',
  data() {
    return {
      rankingData: []
    };
  },
  methods: {
    fetchRankingData() {
      // 模拟 API 请求
      this.rankingData = [
        { name: '李四', points: 200, ranking: 1 },
        { name: '王五', points: 180, ranking: 2 },
        { name: '张三', points: 150, ranking: 3 },
        { name: '赵六', points: 120, ranking: 4 },
        { name: '孙七', points: 100, ranking: 5 }
      ];
    },
    drawChart() {
      const chart = this.$refs.chart;
      const chartInstance = this.$echarts.init(chart);
      const option = {
        title: {
          text: '积分排名',
          left: 'center'
        },
        tooltip: {},
        xAxis: {
          type: 'category',
          data: this.rankingData.map(item => item.name)
        },
        yAxis: {
          type: 'value'
        },
        series: [
          {
            name: '积分',
            type: 'bar',
            data: this.rankingData.map(item => item.points),
            color: '#409EFF'
          }
        ]
      };
      chartInstance.setOption(option);
    }
    },
    mounted() {
      this.fetchRankingData();
      this.$nextTick(() => {
        this.drawChart();
      });
    }
  };
</script>

<style scoped>
.el-header {
  background-color: #409EFF;
  color: white;
  text-align: center;
  line-height: 60px;
}
.el-main {
  padding: 20px;
}
</style>

5. 活动列表

a. ActivityListView.vue
<!-- src/views/ActivityListView.vue -->
<template>
  <el-container>
    <el-header>
      <h2>活动列表</h2>
    </el-header>
    <el-main>
      <el-table :data="activities" style="width: 100%">
        <el-table-column prop="title" label="活动名称" />
        <el-table-column prop="date" label="活动时间" />
        <el-table-column prop="location" label="活动地点" />
        <el-table-column label="操作">
          <template #default="scope">
            <el-button type="primary" @click="goToDetail(scope.row.id)">查看详情</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-main>
  </el-container>
</template>

<script>
export default {
  name: 'ActivityListView',
  data() {
    return {
      activities: []
    };
  },
  methods: {
    fetchActivities() {
      // 模拟 API 请求
      this.activities = [
        {
          id: 1,
          title: '社区清洁活动',
          date: '2023-10-15',
          location: '昆明市'
        },
        {
          id: 2,
          title: '敬老院志愿服务',
          date: '2023-10-20',
          location: '大理市'
        },
        // 其他活动数据...
      ];
    },
    goToDetail(id) {
      this.$router.push({ name: 'activity-detail', params: { id } });
    }
  },
  mounted() {
    this.fetchActivities();
  }
};
</script>

<style scoped>
.el-header {
  background-color: #409EFF;
  color: white;
  text-align: center;
  line-height: 60px;
}
.el-main {
  padding: 20px;
}
</style>

6. 活动详情

a. ActivityDetailView.vue
<!-- src/views/ActivityDetailView.vue -->
<template>
  <el-container>
    <el-header>
      <h2>{{ activity.title }}</h2>
    </el-header>
    <el-main>
      <el-descriptions :column="1" border>
        <el-descriptions-item label="活动时间">{{ activity.date }}</el-descriptions-item>
        <el-descriptions-item label="活动地点">{{ activity.location }}</el-descriptions-item>
        <el-descriptions-item label="描述">{{ activity.description }}</el-descriptions-item>
      </el-descriptions>
      <el-button type="primary" @click="register">报名参加</el-button>
    </el-main>
  </el-container>
</template>

<script>
export default {
  name: 'ActivityDetailView',
  props: {
    id: {
      type: Number,
      required: true
    }
  },
  data() {
    return {
      activity: {}
    };
  },
  methods: {
    fetchActivityDetail() {
      // 模拟 API 请求
      this.activity = {
        id: this.id,
        title: '社区清洁活动',
        date: '2023-10-15',
        location: '昆明市',
        description: '这是一个社区清洁活动,欢迎大家积极参与。'
      };
    },
    register() {
      // 模拟报名逻辑
      this.$message({
        message: '报名成功',
        type: 'success'
      });
    }
  },
  mounted() {
    this.fetchActivityDetail();
  }
};
</script>

<style scoped>
.el-header {
  background-color: #409EFF;
  color: white;
  text-align: center;
  line-height: 60px;
}
.el-main {
  padding: 20px;
}
</style>

7. 我的报名

a. MyRegistrationView.vue
<!-- src/views/MyRegistrationView.vue -->
<template>
  <el-container>
    <el-header>
      <h2>我的报名</h2>
    </el-header>
    <el-main>
      <el-table :data="registrations" style="width: 100%">
        <el-table-column prop="activityTitle" label="活动名称" />
        <el-table-column prop="date" label="活动时间" />
        <el-table-column prop="location" label="活动地点" />
        <el-table-column label="操作">
          <template #default="scope">
            <el-button type="primary" @click="viewDetail(scope.row.id)">查看详情</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-main>
  </el-container>
</template>

<script>
export default {
  name: 'MyRegistrationView',
  data() {
    return {
      registrations: []
    };
  },
  methods: {
    fetchRegistrations() {
      // 模拟 API 请求
      this.registrations = [
        {
          id: 1,
          activityTitle: '社区清洁活动',
          date: '2023-10-15',
          location: '昆明市'
        },
        {
          id: 2,
          activityTitle: '敬老院志愿服务',
          date: '2023-10-20',
          location: '大理市'
        }
      ];
    },
    viewDetail(id) {
      this.$router.push({ name: 'service-record-detail', params: { id } });
    }
  },
  mounted() {
    this.fetchRegistrations();
  }
};
</script>

<style scoped>
.el-header {
  background-color: #409EFF;
  color: white;
  text-align: center;
  line-height: 60

8. 服务记录上传

a. ServiceRecordUploadView.vue
<!-- src/views/ServiceRecordUploadView.vue -->
<template>
  <el-container>
    <el-header>
      <h2>服务记录上传</h2>
    </el-header>
    <el-main>
      <el-form :model="record" label-width="120px">
        <el-form-item label="活动名称">
          <el-input v-model="record.activityTitle" />
        </el-form-item>
        <el-form-item label="服务日期">
          <el-date-picker v-model="record.date" type="date" placeholder="选择日期" />
        </el-form-item>
        <el-form-item label="服务时长">
          <el-input v-model.number="record.duration" />
        </el-form-item>
        <el-form-item label="描述">
          <el-input v-model="record.description" type="textarea" />
        </el-form-item>
        <el-form-item label="上传图片">
          <el-upload
            class="upload-demo"
            action="/api/upload"
            :on-success="handleSuccess"
            :file-list="fileList"
            multiple>
            <el-button type="primary">点击上传</el-button>
          </el-upload>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="submitRecord">提交</el-button>
        </el-form-item>
      </el-form>
    </el-main>
  </el-container>
</template>

<script>
export default {
  name: 'ServiceRecordUploadView',
  data() {
    return {
      record: {
        activityTitle: '',
        date: '',
        duration: 0,
        description: ''
      },
      fileList: []
    };
  },
  methods: {
    handleSuccess(response, file, fileList) {
      this.fileList = fileList;
    },
    submitRecord() {
      // 模拟提交逻辑
      this.$message({
        message: '上传成功',
        type: 'success'
      });
    }
  }
};
</script>

<style scoped>
.el-header {
  background-color: #409EFF;
  color: white;
  text-align: center;
  line-height: 60px;
}
.el-main {
  padding: 20px;
}
</style>

9. 服务记录列表

a. ServiceRecordListView.vue
<!-- src/views/ServiceRecordListView.vue -->
<template>
  <el-container>
    <el-header>
      <h2>服务记录列表</h2>
    </el-header>
    <el-main>
      <el-table :data="records" style="width: 100%">
        <el-table-column prop="activityTitle" label="活动名称" />
        <el-table-column prop="date" label="服务日期" />
        <el-table-column prop="duration" label="服务时长" />
        <el-table-column label="操作">
          <template #default="scope">
            <el-button type="primary" @click="viewDetail(scope.row.id)">查看详情</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-main>
  </el-container>
</template>

<script>
export

10. 服务记录详情

a. ServiceRecordDetailView.vue
<!-- src/views/ServiceRecordDetailView.vue -->
<template>
  <el-container>
    <el-header>
      <h2>服务记录详情</h2>
    </el-header>
    <el-main>
      <el-descriptions :column="1" border>
        <el-descriptions-item label="活动名称">{{ record.activityTitle }}</el-descriptions-item>
        <el-descriptions-item label="服务日期">{{ record.date }}</el-descriptions-item>
        <el-descriptions-item label="服务时长">{{ record.duration }}</el-descriptions-item>
        <el-descriptions-item label="描述">{{ record.description }}</el-descriptions-item>
        <el-descriptions-item label="上传图片">
          <img :src="record.imageUrl" alt="上传图片" style="width: 300px;" />
        </el-descriptions-item>
      </el-descriptions>
    </el-main>
  </el-container>
</template>

<script>
export default {
  name: 'ServiceRecordDetailView',
  props: {
    id: {
      type: Number,
      required: true
    }
  },
  data() {
    return {
      record: {}
    };
  },
  methods: {
    fetchRecordDetail() {
      // 模拟 API 请求
      this.record = {
        activityTitle: '社区清洁活动',
        date: '2023-10-15',
        duration: 3,
        description: '参与了社区清洁活动,清理了街道垃圾。',
        imageUrl: '/assets/images/community-clean.jpg'
      };
    }
  },
  mounted() {
    this.fetchRecordDetail();
  }
};
</script>

<style scoped>
.el-header {
  background-color: #409EFF;
  color: white,

五、综合性案例

1. 综合使用 ECharts 进行数据可视化

在“积分排名”页面中,我们使用了 ECharts 来展示积分排名图表。以下是一个更复杂的图表示例,展示服务记录时长统计:

<!-- src/views/ServiceRecordChartView.vue -->
<template>
  <el-container>
    <el-header>
      <h2>服务记录时长统计</h2>
    </el-header>
    <el-main>
      <div ref="chart" style="width: 100%; height: 400px;"></div>
    </el-main>
  </el-container>
</template>

<script>
export default {
  name: 'ServiceRecordChartView',
  data() {
    return {
      records: []
    };
  },
  methods: {
    fetchRecords() {
      // 模拟 API 请求
      this.records = [
        { activityTitle: '社区清洁活动', duration: 3 },
        { activityTitle: '敬老院志愿服务', duration: 5 },
        { activityTitle: '环保宣传活动', duration: 2 },
        { activityTitle: '社区绿化活动', duration: 4 }
      ];
    },
    drawChart() {
      const chart = this.$refs.chart;
      const chartInstance = this.$echarts.init(chart);
      const option = {
        title: {
          text: '服务记录时长统计',
          left: 'center'
        },
        tooltip: {
          trigger: 'axis'
        },
        xAxis: {
          type: 'category',
          data: this.records.map(item => item.activityTitle)
        },
        yAxis: {
          type: 'value'
        },
        series: [
          {
            name: '时长',
            type: 'bar',
            data: this.records.map(item => item.duration),
            color: '#67C23A'
          }
        ]
      };
      chartInstance.setOption(option);
    }
  },
  mounted() {
    this.fetchRecords();
    this.$nextTick(() => {
      this.drawChart();
    });
  }
};
</script>

<style scoped>
.el-header {
  background-color: #409EFF;
  color: white;
  text-align: center;
  line-height: 60px;
}
.el-main {
  padding: 20px;
}
</style>

2. 使用 Vuex 管理全局状态

在项目中,可以使用 Vuex 来管理用户信息、积分等全局状态。以下是一个简单的 Vuex 示例:

// src/store/index.js
import { createStore } from 'vuex';

const store = createStore({
  state() {
    return {
      userInfo: {
        name: '',
        age: 0,
        email: '',
        points: 0,
        ranking: 0
      }
    };
  },
  mutations: {
    setUserInfo(state, userInfo) {
      state.userInfo = userInfo;
    }
  },
  actions: {
    updateUserInfo({ commit }, userInfo) {
      commit('setUserInfo', userInfo);
    }
  },
  getters: {
    getUserInfo(state) {
      return state.userInfo;
    }
  }
});

export default store;

main.js 中引入 Vuex:

// main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import * as echarts from 'echarts';

const app = createApp(App);

app.use(ElementPlus);
app.use(router);
app.use(store);
app.config.globalProperties.$echarts = echarts;

app.mount('#app');

3. 使用 Axios 进行 HTTP 请求

在项目中,可以使用 Axios 来进行 API 请求。以下是一个示例:

// src/plugins/axios.js
import axios from 'axios';

const service = axios.create({
  baseURL: '/api',
  timeout: 5000
});

export default service;

在组件中使用 Axios:

<!-- src/views/PersonalInfoView.vue -->
<script>
import axios from '../plugins/axios';

export default {
  // ...
  methods: {
    fetchUserInfo() {
      axios.get('/user/info')
        .then(response => {
          this.userInfo = response.data;
        })
        .catch(error => {
          console.error(error);
        });
    },
    saveInfo() {
      axios.post('/user/info', this.userInfo)
        .then(response => {
          this.$message({
            message: '保存成功',
            type: 'success'
          });
        })
        .catch(error => {
          console.error(error);
        });
    }
  },
  mounted() {
    this.fetchUserInfo();
  }
};
</script>

4. 综合应用

以下是一个综合应用示例,展示如何在不同组件之间共享状态并使用 ECharts 进行数据可视化:

<!-- src/views/OverallView.vue -->
<template>
  <el-container>
    <el-header>
      <h2>综合应用示例</h2>
    </el-header>
    <el-main>
      <el-card>
        <h3>用户信息</h3>
        <el-descriptions :column="1" border>
          <el-descriptions-item label="姓名">{{ userInfo.name }}</el-descriptions-item>
          <el-descriptions-item label="年龄">{{ userInfo.age }}</el-descriptions-item>
          <el-descriptions-item label="邮箱">{{ userInfo.email }}</el-descriptions-item>
          <el-descriptions-item label="积分">{{ userInfo.points }}</el-descriptions-item>
          <el-descriptions-item label="排名">{{ userInfo.ranking }}</el-descriptions-item>
        </el-descriptions>
      </el-card>
      <el-card>
        <h3>积分变化趋势</h3>
        <div ref="chart" style="width: 100%; height: 300px;"></div>
      </el-card>
    </el-main>
  </el-container>
</template>

<script>
import axios from '../plugins/axios';
import { mapState, mapActions } from 'vuex';

export default {
  name: 'OverallView',
  data() {
    return {
      chartInstance: null
    };
  },
  computed: {
    ...mapState(['userInfo'])
  },
  methods: {
    ...mapActions(['updateUserInfo']),
    fetchUserInfo() {
      axios.get('/user/info')
        .then(response => {
          this.updateUserInfo(response.data);
        })
        .catch(error => {
          console.error(error);
        });
    },
    drawChart() {
      const chart = this.$refs.chart;
      this.chartInstance = this.$echarts.init(chart);
      const option = {
        title: {
          text: '积分变化趋势',
          left: 'center'
        },
        tooltip: {
          trigger: 'axis'
        },
        xAxis: {
          type: 'category',
          data: ['一月', '二月', '三月', '四月', '五月', '六月']
        },
        yAxis: {
          type: 'value'
        },
        series: [
          {
            name: '积分',
            type: 'line',
            data: [120, 150, 180, 140, 160, 200],
            color: '#409EFF'
          }
        ]
      };
      this.chartInstance.setOption(option);
    }
  },
  mounted() {
    this.fetchUserInfo();
    this.drawChart();
  },
  beforeUnmount() {
    if (this.chartInstance) {
      this.chartInstance.dispose();
    }
  }
};
</script>

<style scoped>
.el-header {
  background-color: #409EFF;
  color: white;
  text-align: center;
  line-height: 60px;
}
.el-main {
  padding: 20px;
}
</style>

六、总结

本文详细介绍了使用 Vue 3、Element Plus、ECharts 和 JavaScript 开发“大学生志愿者服务”项目的具体语法知识点及其使用方法。每个知识点都包含详细的案例代码,并附有详细注释。通过这些内容,您可以更好地理解和应用所学知识,构建功能完善、界面友好的志愿者服务系统。

建议

  • 组件复用:尽量复用组件,提高代码复用性和可维护性。
  • 状态管理:合理使用 Vuex 或 Pinia 管理全局状态,避免数据混乱。
  • 响应式设计:确保应用在不同设备上的良好展示。
  • 性能优化:使用懒加载、代码分割等技术优化应用性能。
  • 安全性:注意 API 接口的安全性,防止数据泄露和恶意攻击。

希望本文对您开发“大学生志愿者服务”项目有所帮助。如果有任何疑问或需要进一步的帮助,请随时提问。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐