vue.js下拉框绑定数据库

admin 102 0
Vue.js中下拉框绑定数据库需先通过axios或fetch从后端接口获取数据,存储于组件data属性,使用v-model绑定下拉框选中值至组件数据,通过v-for动态渲染选项列表,如{{item.label}},需处理数据加载状态(如loading)、错误捕获,并在选中值变化时触发回调(@change事件),结合Vue的响应式特性,实现数据与视图的双向绑定,确保下拉框选项随数据库更新而动态刷新,提升交互性与数据一致性。

Vue.js 下拉框绑定数据库数据实战教程

在Web开发中,下拉框(Select)作为核心表单组件,广泛应用于选项选择场景,当选项数据需从数据库动态获取时,如何高效实现Vue.js与数据库数据的双向绑定,成为开发者必须掌握的关键技能,本文基于Vue 3组合式API,结合Axios请求后端接口,系统讲解下拉框绑定数据库数据的完整实现方案,涵盖环境搭建、接口对接、数据渲染及异常处理等全流程。


环境准备与技术栈

开发环境要求

组件 版本要求 说明
前端 Node.js v14+ JavaScript运行环境
Vue CLI v5+ Vue项目脚手架
后端 Node.js + Express 或Spring Boot/Django等
数据库 MySQL 8.0+ 或MongoDB/PostgreSQL
核心依赖 Vue 3、Axios HTTP请求库
Express、mysql2 后端框架与数据库驱动

项目初始化

# 创建Vue 3项目
npm create vue@latest vue-select-demo
cd vue-select-demo
npm install
# 安装Axios
npm install axios

后端接口设计与数据库准备

数据库表设计

CREATE TABLE `user_types` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `type_name` VARCHAR(50) NOT NULL COMMENT '显示名称',
  `type_code` VARCHAR(20) NOT NULL COMMENT '唯一标识',
  `sort_order` INT DEFAULT 0 COMMENT '排序权重',
  `status` TINYINT DEFAULT 1 COMMENT '状态(1启用/0禁用)',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_type_code` (`type_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户类型表';
-- 插入测试数据
INSERT INTO `user_types` (`type_name`, `type_code`, `sort_order`) VALUES 
('超级管理员', 'super_admin', 1),
('普通用户', 'user', 2),
('访客', 'guest', 3),
('测试账号', 'test', 4);

后端接口开发(Node.js + Express)

项目结构:

server/
├── db.js              # 数据库连接池
├── index.js           # 服务入口
└── routes/
    └── userTypes.js   # 用户类型路由

数据库配置(db.js):

const mysql = require('mysql2/promise');
const pool = mysql.createPool({
  host: 'localhost',
  user: 'root',
  password: 'your_password',
  database: 'your_database',
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0
});
module.exports = pool;

路由实现(userTypes.js):

const express = require('express');
const router = express.Router();
const db = require('../db');
// 获取用户类型列表(含状态过滤)
router.get('/api/user-types', async (req, res) => {
  try {
    const { status = 1 } = req.query;
    const [rows] = await db.query(
      `SELECT id, type_name AS label, type_code AS value 
       FROM user_types 
       WHERE status = ? 
       ORDER BY sort_order ASC`,
      [status]
    );
    res.json({
      code: 200,
      data: rows,
      message: '获取成功'
    });
  } catch (error) {
    console.error('数据库查询错误:', error);
    res.status(500).json({
      code: 500,
      message: '服务器错误',
      error: error.message
    });
  }
});
module.exports = router;

服务入口(index.js):

const express = require('express');
const cors = require('cors');
const userTypeRoutes = require('./routes/userTypes');
const app = express();
app.use(cors());
app.use(express.json());
app.use(userTypeRoutes);
const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Server running at http://localhost:${PORT}`);
});

启动后端服务:

cd server
npm install express mysql2 cors
node index.js

接口测试结果:

{
  "code": 200,
  "data": [
    {"id": 1, "label": "超级管理员", "value": "super_admin"},
    {"id": 2, "label": "普通用户", "value": "user"},
    {"id": 3, "label": "访客", "value": "guest"},
    {"id": 4, "label": "测试账号", "value": "test"}
  ],
  "message": "获取成功"
}

Vue前端实现

Axios请求封装(utils/request.js)

import axios from 'axios';
import { ElMessage } from 'element-plus';
const instance = axios.create({
  baseURL: 'http://localhost:3000',
  timeout: 10000
});
// 响应拦截器
instance.interceptors.response.use(
  response => {
    const { code, data, message } = response.data;
    if (code === 200) return data;
    ElMessage.error(message || '请求失败');
    return Promise.reject(new Error(message));
  },
  error => {
    ElMessage.error(error.response?.data?.message || '网络错误');
    return Promise.reject(error);
  }
);
export default instance;

下拉框组件实现(components/UserTypeSelect.vue)

<template>
  <div class="user-type-select">
    <h3>用户类型选择</h3>
    <!-- 加载状态 -->
    <div v-if="loading" class="loading">
      <el-icon class="is-loading"><loading /></el-icon>
      加载中...
    </div>
    <!-- 错误提示 -->
    <el-alert 
      v-else-if="error" 
      :title="error" 
      type="error" 
      show-icon 
      @close="error = ''"
    />
    <!-- 下拉框主体 -->
    <el-select
      v-else
      v-model="selectedValue"
      placeholder="请选择用户类型"
      filterable
      clearable
      remote
      :remote-method="remoteSearch"
      :loading="remoteLoading"
      @change="handleChange"
    >
      <el-option
        v-for="item in options"
        :key="item.value"
        :label="item.label"
        :value="item.value"
      >
        <div class="option-item">
          <span>{{ item.label }}</span>
          <el-tag size="small" type="info">{{ item.value }}</el-tag>
        </div>
      </el-option>
    </el-select>
    <!-- 选中值展示 -->
    <div v-if="selectedValue" class="selected-info">
      当前选择: <strong>{{ selectedLabel }}</strong>
      <el-button 
        type="primary" 
        size="small" 
        @click="handleConfirm"
      >
        确认
      </el-button>
    </div>
  </div>
</template>
<script setup>
import { ref, onMounted, computed } from 'vue';
import request from '@/utils/request';
// 组件属性定义
const props = defineProps({
  modelValue: {
    type: [String, Number],
    default: