vue-day09

vue-day09

1-UI组件库element-ui

1.1-安装

npm i element-ui -S

1.2-使用

1.2.1-完整引入

main.js

import Vue from 'vue';
// 1.导入核心包
import ElementUI from 'element-ui';
// 2-导入样式表
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';
// 3-注册插件
Vue.use(ElementUI);

1.2.2-按需引入

  1. 安装一个babel的插件babel-plugin-component

    npm i babel-plugin-component -D
    
  2. 打开babel配置文件.babelrc, 做如下修改

    {
      "presets": [
        ["env", {
          "modules": false,
          "targets": {
            "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
          }
        }],
        "stage-2"
      ],
      "plugins": [
        "transform-vue-jsx", 
        "transform-runtime",
        // element-ui按需导入配置
       + [
       +   "component",
       +   {
       +     "libraryName": "element-ui",
       +     "styleLibraryName": "theme-chalk"
       +   }
       + ]
      ]
    }
    
  3. 重启开发服务器

    npm run dev
    
  4. 按需导入组件

    import Vue from 'vue'
    // 按需导入组件
    import { Button,Divider,Calendar,Carousel,CarouselItem } from 'element-ui'
    // 注册组件
    Vue.use(Button);
    Vue.use(Divider);
    Vue.use(Calendar);
    Vue.use(Carousel);
    Vue.use(CarouselItem);
    

2-项目开发环境的搭建

2.1-数据接口服务器搭建

  1. 下载shop-api.zip

  2. 解压

  3. 进入项目根目录, 安装项目依赖

    npm i
    
  4. 导入数据库

  5. 打开项目配置文件/config/global.js

    // 数据库连接参数
    exports.dbConfig = {
        host: 'localhost', //数据库地址
        user: 'root',//数据库用户名
        password: 'root',//数据库用户密码
        port: 3306,
        database: 'shop-db' // 数据库名字
    }
    
  6. 启动项目

    数据接口服务器访问地址: http://localhost:3000

    参考项目访问地址:http://localhost:3000/admin

    npm start
    

2.2-前端开发环境的搭建

  1. 通过vue-cli脚手架初始化一个全新的项目

    vue init webpack vue-element-admin
    
  2. 安装依赖项

    npm i element-ui vuex axios -S
    

2.3-准备工作

2.3.0-配置跨域代理服务器
2.3.1-全部引入element-ui

utils/element.js

// 全部导入
import Vue from 'vue';
import element from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// 注册
Vue.use(element);

// 封装一个成功提示
Vue.prototype.$success=function(message){
    this.$message({
        type:'success',
        message
    });
}    

// 封装一个失败提示
Vue.prototype.$error=function(message){
    this.$message({
        type:'error',
        message
    });
}    
2.3.2-重置样式

assets/css/reset.css

*{
    padding: 0;
    margin: 0;
    box-sizing: border-box;
}
a{
    text-decoration: none;
}
li{
    list-style: none;
}
2.3.3-封装axios

utils/http.js

//axios的二次封装
import Vue from 'vue';

import axios from 'axios';

// 导入element-ui中的消息提示方法
import { Message } from 'element-ui';

// 配置基础域名
axios.defaults.baseURL='http://localhost:3000/api';


axios.interceptors.request.use(function(config){
    const loginInfo=JSON.parse(localStorage.getItem('loginInfo')||'{}');
    // 必须通过自定义请求头authorization, 将登录凭证发送给数据接口
    config.headers.authorization=loginInfo.token;
    return config;
});

// 响应拦截器
axios.interceptors.response.use(function(response){
    // 登录超时
    if(response.data.code===403){
        // 消息提示
        Message({type:'warning',message:response.data.msg});
        // 将页面重定向到登录页面
        location.href='#/login';
    }
    return  response.data
});

// 将axios挂载到vue的原型对象上
Vue.prototype.$http=axios;

// 导出
export default axios;
2.3.4-引入vuex

store/index.js

// 1-导入
import Vue from 'vue';
import Vuex from 'vuex';

// 2-注册
Vue.use(Vuex);

// 导入子模块
import menu from './modules/menu'

// 3-创建数据存储对象
const store=new  Vuex.Store({
    state:{},
    mutations:{},
    getter:{},
    actions:{},
    modules:{
        menu
    }
});

// 4-导出
export default store;

store/modules/menu.js

// 导入数据请求方法
import { getMenuList } from '../../request/menu'
export default {
    // 开启独立的命名空间
    namespaced:true,
    state(){
        return {
            // 菜单列表
            menuList:[]
        }
    },
    mutations:{
        // 菜单初始化的方式
        menuInit(state,list){
            state.menuList=list;
        }
    },
    actions:{
        // 请求菜单列表
        getMenuListAction({commit}){
            getMenuList().then(res=>{
                if(res){
                    commit('menuInit',res)
                }
            });
        }
    },
    getters:{

    }
}

3-登录

3.1-登录页面布局

pages/Login.vue

<template>
  <div class="login-container">
    <div class="login-box">
      <h3 class="login-title">小U商城后台管理系统</h3>
      <el-form
        :model="formData"
        :rules="rules"
        ref="loginRef"
        class="login-form"
      >
        <!-- prop: 指定错误消息的显示位置 -->
        <el-form-item prop="username">
          <el-input type="text" placeholder="请输入登录账号" v-model="formData.username" autocomplete="off">
            <template slot="prepend">
              <i class="el-icon-user-solid"></i>
            </template>
          </el-input>
        </el-form-item>
        <el-form-item prop="password">
          <el-input type="password" placeholder="请输入密码" v-model="formData.password" autocomplete="off">
            <template slot="prepend">
              <i class="el-icon-lock"></i>
            </template>
          </el-input>
        </el-form-item>
        <el-form-item>
          <el-button class="btn-login" type="primary" @click="submitForm">提交</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      formData: {
        username: "",
        password: ""
      },
      // 表单校验规则
      rules: {
        username: {required:true,message:'请输入登录账号',trigger:'blur'},
        password: {required:true,message:'请输入登录密码',trigger:'blur'},
      }
    };
  },
  methods: {
    submitForm(formName) {
      // validate: 进行终极表单校验
      // valid: 系统形参, true表单校验通过, false表单校验不通过
      this.$refs.loginRef.validate(valid => {
        if (valid) {
          alert("submit!");
        } else {
          console.log("error submit!!");
          return false;
        }
      });

    }
  }
};
</script>

<style scoped>
.login-container {
  /* vh: viewport height, 是一个相对单位; 100vh=屏幕高度 1vh=1/100屏幕高度 */
  height: 100vh;
  background: url("../assets/imgs/loginbg.jpg");
  background-size: 100% 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}
.login-box {
  width: 400px;
  height: 300px;
  background: #fff;
  border-radius: 4px;
  padding:0 30px;
}
.login-title {
  color: #409eff;
  text-align: center;
  margin-top: 40px;
}
.login-form{
  margin-top: 40px;
}
.btn-login{
  width: 100%;
}
</style>

3.2-登录功能的实现

<template>
  <div class="login-container">
    <div class="login-box">
      <h3 class="login-title">小U商城后台管理系统</h3>
      <el-form
        :model="formData"
        :rules="rules"
        ref="loginRef"
        class="login-form"
      >
        <!-- prop: 指定错误消息的显示位置 -->
        <el-form-item prop="username">
          <el-input type="text" placeholder="请输入登录账号" v-model="formData.username" autocomplete="off">
            <template slot="prepend">
              <i class="el-icon-user-solid"></i>
            </template>
          </el-input>
        </el-form-item>
        <el-form-item prop="password">
          <el-input type="password" show-password placeholder="请输入密码" v-model="formData.password" autocomplete="off">
            <template slot="prepend">
              <i class="el-icon-lock"></i>
            </template>
          </el-input>
        </el-form-item>
        <el-form-item>
          <el-button class="btn-login" type="primary" @click="submitForm">提交</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      formData: {
        username: "",
        password: ""
      },
      // 表单校验规则
      rules: {
        username: {required:true,message:'请输入登录账号',trigger:'blur'},
        password: {required:true,message:'请输入登录密码',trigger:'blur'},
      }
    };
  },
  methods: {
    submitForm(formName) {
      // validate: 进行终极表单校验
      // valid: 系统形参, true表单校验通过, false表单校验不通过
      this.$refs.loginRef.validate(valid => {
        if (valid) {
          this.$http.post('/userlogin',this.formData).then(res=>{
            if(res.code===200){
              // 1-将用户相关信息存储到本地存储localStorage中
              localStorage.setItem('loginInfo',JSON.stringify(res.list));
              // 2-给出成功提示
              this.$success(res.msg);
              // 3-跳转到管理中心
              this.$router.push('/');
            }
          })
        } else {
          console.log("error submit!!");
          return false;
        }
      });

    }
  }
};
</script>

4-管理中心

4.1-管理中心页面布局

pages/Layout.vue

<template>
  <el-container>
    <el-aside width="226px">
      <h3 class="logo-text">小U商城后台</h3>
      <!-- 主导航 -->
      <el-menu
        default-active="2"
        class="el-menu-vertical-demo"
        @open="handleOpen"
        @close="handleClose"
        background-color="#333"
        text-color="#FFF"
        active-text-color="#FFF"
        router
      >
        <el-menu-item index="1">
          <i class="el-icon-menu"></i>
          <span slot="title">管理中心</span>
        </el-menu-item>

        <el-submenu index="2">
          <template slot="title">
            <i class="el-icon-setting"></i>
            <span>系统设置</span>
          </template>
          <el-menu-item index="/menu">
            <span slot="title">菜单管理</span>
          </el-menu-item>
          <el-menu-item index="2-2">
            <span slot="title">角色管理</span>
          </el-menu-item>
          <el-menu-item index="2-3">
            <span slot="title">管理员管理</span>
          </el-menu-item>
        </el-submenu>

        <el-submenu index="3">
          <template slot="title">
            <i class="el-icon-goods"></i>
            <span>商城管理</span>
          </template>
          <el-menu-item index="3-1">
            <span slot="title">分类管理</span>
          </el-menu-item>
          <el-menu-item index="3-2">
            <span slot="title">规格管理</span>
          </el-menu-item>
          <el-menu-item index="3-3">
            <span slot="title">商品管理</span>
          </el-menu-item>
          <el-menu-item index="3-4">
            <span slot="title">轮播图管理</span>
          </el-menu-item>
          <el-menu-item index="3-5">
            <span slot="title">会员管理</span>
          </el-menu-item>
          <el-menu-item index="3-6">
            <span slot="title">活动管理</span>
          </el-menu-item>
        </el-submenu>
      </el-menu>
    </el-aside>
    <el-container>
      <el-header>
        <el-button type="primary" icon="el-icon-s-fold" size="mini"></el-button>
        <el-breadcrumb separator="/">
          <el-breadcrumb-item>管理中心</el-breadcrumb-item>
          <el-breadcrumb-item>页面标题</el-breadcrumb-item>
        </el-breadcrumb>
        <el-button icon="el-icon-back" size="mini" circle></el-button>

        <el-dropdown>
          <span class="el-dropdown-link">
            admin
            <i class="el-icon-arrow-down el-icon--right"></i>
          </span>
          <el-dropdown-menu slot="dropdown">
            <el-dropdown-item>个人信息</el-dropdown-item>
            <el-dropdown-item>全屏预览</el-dropdown-item>
            <el-dropdown-item>安全退出</el-dropdown-item>
          </el-dropdown-menu>
        </el-dropdown>
      </el-header>
      <el-main>

          <!-- 二级路由占位符 -->
           <router-view /> 

      </el-main>
    </el-container>
  </el-container>
</template>

<script>
export default {
  methods: {
    handleOpen(key, keyPath) {
      console.log(key, keyPath);
    },
    handleClose(key, keyPath) {
      console.log(key, keyPath);
    }
  }
};
</script>

<style scoped>
.el-container {
  height: 100vh;
}

/* logo */
.logo-text {
  background: #444;
  color: #fff;
  line-height: 60px;
  font-weight: normal;
  letter-spacing: 3px;
  text-align: center;
}

/* 导航 */
.el-menu {
  height: calc(100vh - 60px);
  border-right: none;
}
/* 导航高亮类名 */
.is-active {
  background: #409eff !important;
}
/* 页面头部 */
.el-header {
  background-color: #fff;
  line-height: 60px;
  display: flex;
  align-items: center;
}
.el-header button {
  height: 26px;
}
.el-breadcrumb {
  margin:0 20px;
}
.el-dropdown{
    position: absolute;
    right:20px;
}

.el-aside {
  background-color: #d3dce6;
  color: #333;
}

.el-main {
  background-color: #e9eef3;
  color: #333;
}
</style>

5-菜单管理

5.0-数据请求方法封装

request/menu.js

import axios from '../utils/http';
// 获取菜单列表
export async function getMenuList(){
   const res=await axios.get('/menulist?istree=1');
   if(res.code===200){
      return res.list;  
   }
   return false;
}

5.1-菜单列表

pages/menu/Index.vue

<template>
  <el-card>
    <el-button @click="showModal" icon="el-icon-circle-plus-outline" type="primary">新增</el-button>
    <el-divider/>
    <!-- tree-props: 指定二级菜单数据存储的属性节点名称 -->
     <el-table
    :data="menuList"
    style="width: 100%;margin-bottom: 20px;"
    row-key="id"
    :tree-props="{children: 'children'}">
    <el-table-column
      prop="id"
      label="id"
      width="180">
    </el-table-column>
    <el-table-column
      prop="title"
      label="标题"
      width="180">
    </el-table-column>
    <el-table-column
      prop="icon"
      label="图标">
      <!-- 接收组件内部分发出来的数据 -->
      <template v-slot="props">
          <i :class="props.row.icon"></i>
      </template>
    </el-table-column>
    <el-table-column
      prop="status"
      label=" 状态">
       <template v-slot="props">
          <el-tag v-if="props.row.status===1" type="success">正常</el-tag>
          <el-tag v-else type="danger">禁用</el-tag>
      </template>
    </el-table-column>
    <el-table-column
      prop="url"
      label="地址">
    </el-table-column>
    <el-table-column
      label="操作">
      <el-button circle size="mini" icon="el-icon-delete" type="danger"></el-button>
      <el-button circle size="mini" icon="el-icon-edit" type="success"></el-button>
    </el-table-column>
  </el-table>

    <!-- 调用对话框组件  -->
    <Modal :info="info" @updateList="updateList"/>
  </el-card>
</template>

<script>
import Modal from './Modal';
import { mapState,mapActions } from 'vuex';
export default {
  components:{
    Modal
  },
  created(){
    this.getMenuListAction();
  },  
  computed:{
    ...mapState({menuList:state=>state.menu.menuList})
  },
  methods:{
    ...mapActions('menu',['getMenuListAction']),
    showModal(){
       this.info.isShow=!this.info.isShow; 
    },
    // 自定义事件updateList的处理函数
    updateList(){
        this.getMenuListAction();
    }
  },
  data(){
    return {
      info:{
        isShow:false
      }
    }
  }
}
</script>

<style>

</style>

5.2-菜单添加

pages/menu/Modal.vue

<template>
  <el-dialog @close="resetForm" title="收货地址" :visible.sync="info.isShow">
    <el-form ref="menuForm" :model="formData" :rules="rules" label-width="60px">
      <el-form-item label="类型" prop="type">
        <el-radio-group v-model="formData.type">
            <el-radio :label="1">目录</el-radio>
            <el-radio :label="2">菜单</el-radio>
        </el-radio-group>
      </el-form-item>

      <el-form-item label="上级" v-if="formData.type===2" prop="pid">
        <el-select placeholder="请选择" v-model="formData.pid">
            <el-option :value="0" label="请选择"></el-option>
            <el-option
            v-for="item in menuList"
            :key="item.id"
            :label="item.title"
            :value="item.id">
            </el-option>
        </el-select>
      </el-form-item>

      <el-form-item label="名称" prop="title">
        <el-input placeholder="菜单标题" v-model="formData.title"></el-input>
      </el-form-item> 

      <el-form-item label="图标" v-if="formData.type===1" prop="icon">
        <el-input placeholder="图标" v-model="formData.icon"></el-input>
      </el-form-item> 

      <el-form-item label="地址" v-if="formData.type===2" prop="url">
        <el-input placeholder="地址" v-model="formData.url"></el-input>
      </el-form-item> 

      <el-form-item label="状态" prop="status">
        <el-radio-group v-model="formData.status">
            <el-radio :label="1">正常</el-radio>
            <el-radio :label="2">禁用</el-radio>
        </el-radio-group>
      </el-form-item>

    </el-form>
    <div slot="footer" class="dialog-footer">
      <el-button @click="info.isShow = false">取 消</el-button>
      <el-button type="primary" @click="submit">确 定</el-button>
    </div>
  </el-dialog>
</template>

<script>
import { mapState } from 'vuex';
export default {
  computed:{
      ...mapState({menuList:state=>state.menu.menuList})
  },
  // 接收父组件传递过来的数据 
  props: ['info'],
  data() {
    return {
       // 和表单元素进行绑定 
      formData: {
          pid:0,
          title:'',
          icon:'',
          status:'',
          type:1,
          url:''
      },
      // 表单校验规则  
      rules:{
         title:{required:true,message:'请输入名称',trigger:'blur'},
         status:{required:true,message:'请选择状态',trigger:'blur'}
      }
    };
  },
  methods:{
      //   表单提交
      submit(){
          this.$refs.menuForm.validate(valid=>{
              if(valid){
                //  提交表单
                this.$http.post('/menuadd',this.formData).then(res=>{
                    if(res.code===200){
                        this.$success(res.msg);
                        // 1-关闭对话框组件
                        this.info.isShow=false;
                        // 2-更新数据列表
                        this.$emit('updateList')
                    }else{
                        this.$error(res.msg);
                    }
                })
              }
          });
      },
      resetForm(){
          //   重置表单
          this.$refs.menuForm.resetFields();
      }
  }
};
</script>

<style>
</style>

参考文档

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值