• 结合 element-ui 对 Vue 相关知识点整理 (router,axios,Vuex )


    element-ui 安装

    npm i element-ui -S

    安装 css 之类的相关的依赖

    npm install  sass-loader@7.3.1 node-sass --save-dev 

    引入使用

    标红色的部分是引入的代码. 在项目的 main.js 里面

    // The Vue build version to load with the `import` command
    // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
    import Vue from 'vue'
    import App from './App'
    import router from './router'
    import ElementUI from 'element-ui'
    import 'element-ui/lib/theme-chalk/index.css'
    
    Vue.use(ElementUI)
    Vue.config.productionTip = false
    
    /* eslint-disable no-new */
    new Vue({
      el: '#app',
      router,
      components: {App},
      template: '<App/>',
      render: h => h(App)
    })

    简单的登录页面实现以及校验功能

    主要是使用 element-ui 的form 组件功能的验证以及一些消息提示

    <template>
      <el-form ref="form" :model="form" :rules="rules" class="login-box">
        <h3 class="login-title">欢迎登录</h3>
        <el-form-item label="账号" prop="name">
          <el-input type="text" aria-placeholder="请输入用户名" v-model="form.name"></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input type="password" aria-placeholder="请输入密码" v-model="form.password"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="submitForm('form')">登录</el-button>
        </el-form-item>
    
      </el-form>
    </template>
    
    <script>
      export default {
        name: "Login",
        data() {
          return {
            form: {
              name: "",
              password: ""
            },
            rules: {
              name: [
                {required: true, message: '请输入用户名称', trigger: 'blur'},
              ],
              password: [
                {required: true, message: '请输入密码', trigger: 'blur'},
              ]
            }
          }
        },
        methods: {
          submitForm(formName) {
            this.$refs[formName].validate((valid) => {
              if (valid) {
                this.$router.push("/main")
              } else {
                this.$message({
                  message: '用户名或者密码未填',
                  type: 'warning'
                });
                return false;
              }
            });
          },
        }
      }
    </script>
    
    <style scoped>
      .login-box {
        width: 350px;
        margin: 150px auto;
        border: 1px solid #DCDFE6;
        padding: 20px;
        border-radius: 5px;
        box-shadow: 0 0 30px #DCDFE6;
      }
    
      .login-title {
        text-align: center;
      }
    
    </style>

    展示效果

    校验失败的提示效果, 成功后就自动跳转到 /main 页面, 即首页页面的组件

    首页简单实现

    布局

    基于官方的示例, 实现一个简单的左侧导航栏, 右侧内容展示, 头部展示一个title 的一个布局

    相关代码

    main.vue 

    main 组件还是用 element-ui 的相关方法来拼

    <template>
      <div>
        <el-container>
          <el-aside width="200px">
            <el-menu :default-openeds="['1']">
              <el-submenu index="1">
                <template slot="title"><i class="el-icon-message"></i>羊驼产品</template>
                <el-menu-item-group>
                  <el-menu-item index="1-1">
                    <router-link to="/member/type">羊驼型号</router-link>
                  </el-menu-item>
                  <el-menu-item index="1-2">
    
                    <router-link to="/member/list">羊驼列表</router-link>
                  </el-menu-item>
    
                </el-menu-item-group>
              </el-submenu>
              <el-submenu index="2">
                <template slot="title"><i class="el-icon-message"></i>羊驼园区</template>
                <el-menu-item-group>
                  <el-menu-item index="2-1">园区分布</el-menu-item>
                  <el-menu-item index="2-2">园区列表</el-menu-item>
                </el-menu-item-group>
              </el-submenu>
            </el-menu>
    
          </el-aside>
          <el-container>
            <el-header style="text-align: right; font-size: 12px">
              <el-dropdown>
                <i class="el-icon-setting" style="margin-right: 15px"></i>
                <el-dropdown-menu slot="dropdown">
                  <el-dropdown-item>用户中心</el-dropdown-item>
                  <el-dropdown-item>退出登录</el-dropdown-item>
                </el-dropdown-menu>
              </el-dropdown>
              <span>admin</span>
            </el-header>
    
            <el-main>
              <router-view/>
            </el-main>
          </el-container>
        </el-container>
      </div>
    
    
    </template>
    
    <script>
      export default {
        name: "Main"
      }
    </script>
    
    <style scoped>
      .el-header {
        background-color: #B3C0D1;
        color: #333;
        line-height: 60px;
      }
    
      .el-aside {
        color: #333;
      }
    </style>

    子路由

     index.js  子路由相关代码

    /main 下的子路由用   children  来作为关键字传入

    import Vue from 'vue'
    import Router from 'vue-router'
    import Login from "../views/Login";
    import Main from "../views/Main";
    import MemberList from "../views/Member/MemberList";
    import MemberType from "../views/Member/MemberType";
    
    
    Vue.use(Router)
    
    export default new Router({
      routes: [
        {
          path: '/login',
          name: 'Login',
          component: Login
        },
        {
          path: '/main',
          name: 'Main',
          component: Main,
          children: [
            {
              path: '/member/list',
              name: 'MemberList',
              component: MemberList
            },
            {
              path: '/member/type',
              name: 'MemberType',
              component: MemberType
            }
          ]
        },
    
      ]
    })

    组件间参数传递方式

    路径匹配

    link to 的时候传递参数

     <router-link to="/member/type/1">羊驼型号</router-link>

    路由路径的时候

      指定参数

          {   
              path: '/member/type/:id',
              name: 'MemberType',
              component: MemberType
            }

    组件内参数的使用

      通过 $route.params.id 进行调用

    <template>
      <div>羊驼类型  ID={{$route.params.id}}</div>
    </template>

    展示效果

    porps 方式

    link to 部分改为对象

      name 固定参数传递的是跳转组件的 name

      params 固定参数表示传入的参数, 格式为对象, 里面为具体传入的参数

      <router-link :to="{name:'MemberType', params: {id: 3}}">羊驼型号</router-link>

     路由的部分

      添加一个 props 为 true

    {
              path: '/member/type/:id',
              name: 'MemberType',
              component: MemberType,
              props: true
    }

    组件内参数的使用

    声明出来一个 props , 然后模板里面就可以简单的直接用 参数了

    <template>
      <div>羊驼类型 ID={{id}}</div>
    </template>
    
    <script>
      export default {
        name: "MemberType",
        props: ["id"]
    
      }
    </script>

     展示效果

    porps 方法内的使用

    应用场景示例

    这里登陆后的跳转时, 把登录后的用户名传递过来在首页显示出来, 之前是写死的 admin

    代码

    login 的跳转代码调整为对象

    submitForm(formName) {
            this.$refs[formName].validate((valid) => {
              if (valid) {
                this.$router.push({name: "Main", params: {username: this.form.name}})
              } else {
                this.$message({
                  message: '用户名或者密码未填',
                  type: 'warning'
                });
                return false;
              }
            });
          },

    路由里面打开 props 

        {
          path: '/main/',
          name: 'Main',
          component: Main,
          props: true,
          children: [
            {
              path: '/member/list',
              name: 'MemberList',
              component: MemberList
            },
            {
              path: '/member/type/:id',
              name: 'MemberType',
              component: MemberType,
              props: true
            }
          ]
        },

    main 组件里面接受使用

       <span>{{username}}</span>
      export default {
        name: "Main",
        props: ["username"]
      }

    实现效果

    login 的时候用户名为 yangtuo

    登录后

    路由重定向

    main 需要接受一个 :username 的参数

    {
          path: '/main/:username',
          name: 'Main',
    ....

    路由设置, 将一个 username 的参数重定向传递给 main 

        {
          path: '/remain/:username',
          redirect: '/main/:username'
        }

    多加一个按钮来指向这个路径, 这里假设传递一个 admin123的参数

     <el-menu-item index="1-3">
          <router-link to="/goHome/admin123">回到首页</router-link>
     </el-menu-item>

    展示效果

    路由模式处理

    默认的这种单文件之间的组件跳转的页面 url 里面会有个 # 

     

    相关处理

    在路由里面的 mode 使用 历史模式即可去除 

    export default new Router({
      mode: "history",
    ....

    效果展示

    统一 404 处理

    代码

    <template>
        <div> 假设一个很好看的 404 提示页面</div>
    </template>
    
    <script>
        export default {
            name: "NotFound"
        }
    </script>
    
    <style scoped>
    
    </style>
    {
          path: "*",
          name: 'NotFound',
          component: NotFound
    }

     效果展示

    路由钩子函数进行异步请求

    钩子函数的定义

    所有的钩子函数

    相关的调用过程可以用此代码调试

    <!DOCTYPE html>
    <html>
    <head>
        <title></title>
        <script type="text/javascript" src="https://cdn.jsdelivr.net/vue/2.1.3/vue.js"></script>
    </head>
    <body>
    
    <div id="app">
         <p>{{ message }}</p>
    </div>
    
    <script type="text/javascript">
        
      var app = new Vue({
          el: '#app',
          data: {
              message : "xuxiao is boy" 
          },
           beforeCreate: function () {
                    console.group('beforeCreate 创建前状态===============》');
                   console.log("%c%s", "color:red" , "el     : " + this.$el); //undefined
                   console.log("%c%s", "color:red","data   : " + this.$data); //undefined 
                   console.log("%c%s", "color:red","message: " + this.message)  
            },
            created: function () {
                console.group('created 创建完毕状态===============》');
                console.log("%c%s", "color:red","el     : " + this.$el); //undefined
                   console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化 
                   console.log("%c%s", "color:red","message: " + this.message); //已被初始化
            },
            beforeMount: function () {
                console.group('beforeMount 挂载前状态===============》');
                console.log("%c%s", "color:red","el     : " + (this.$el)); //已被初始化
                console.log(this.$el);
                   console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化  
                   console.log("%c%s", "color:red","message: " + this.message); //已被初始化  
            },
            mounted: function () {
                console.group('mounted 挂载结束状态===============》');
                console.log("%c%s", "color:red","el     : " + this.$el); //已被初始化
                console.log(this.$el);    
                   console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化
                   console.log("%c%s", "color:red","message: " + this.message); //已被初始化 
            },
            beforeUpdate: function () {
                console.group('beforeUpdate 更新前状态===============》');
                console.log("%c%s", "color:red","el     : " + this.$el);
                console.log(this.$el);   
                   console.log("%c%s", "color:red","data   : " + this.$data); 
                   console.log("%c%s", "color:red","message: " + this.message); 
            },
            updated: function () {
                console.group('updated 更新完成状态===============》');
                console.log("%c%s", "color:red","el     : " + this.$el);
                console.log(this.$el); 
                   console.log("%c%s", "color:red","data   : " + this.$data); 
                   console.log("%c%s", "color:red","message: " + this.message); 
            },
            beforeDestroy: function () {
                console.group('beforeDestroy 销毁前状态===============》');
                console.log("%c%s", "color:red","el     : " + this.$el);
                console.log(this.$el);    
                   console.log("%c%s", "color:red","data   : " + this.$data); 
                   console.log("%c%s", "color:red","message: " + this.message); 
            },
            destroyed: function () {
                console.group('destroyed 销毁完成状态===============》');
                console.log("%c%s", "color:red","el     : " + this.$el);
                console.log(this.$el);  
                   console.log("%c%s", "color:red","data   : " + this.$data); 
                   console.log("%c%s", "color:red","message: " + this.message)
            }
        })
    </script>
    </body>
    </html>

    钩子函数的参数 , to. from. next. 分别表示 要去的路由, 从那个路由来的, 以及控制路由的参数

      export default {
        name: "MemberType",
        props: ["id"],
        beforeRouteEnter: (to, from, next) => {
    
        },
        beforeRouteLeave: (to, from, next) => {
        },
      }

    axios 相关准备

     异步请求需要 axios 安装

    cnpm install axios -s

     引用 axios

    import axios from "axios";
    
    Vue.prototype.axios = axios

    配合钩子函数使用进行异步请求

    后端准备

    既然是异步请求则需要一个后端, 这里后端起一个 django 随便编写一些简单的数据进行回应

    前后端的跨域问题让 django 的后端来处理. 从而让前段完全不需要操作好了

    安装跨域相关处理的包

    pip install django-cors-headers

    添加进去 app中 

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'user.apps.UserConfig',
        'rest_framework',
        'django_filters',
        'coreapi',
        'corsheaders'
    ]

    然后注册中间件, 注意放的位置, 放错了就不会生效了

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'corsheaders.middleware.CorsMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]

    settings.py 里面对跨域的限制的相关配置

    ALLOWED_HOSTS = ["*"]
    # 增加跨域忽略
    CORS_ALLOW_CREDENTIALS = True
    CORS_ORIGIN_ALLOW_ALL = True
    
    CORS_ALLOW_METHODS = (
        'DELETE',
        'GET',
        'OPTIONS',
        'PATCH',
        'POST',
        'PUT',
        'VIEW',
    )
    CORS_ALLOW_HEADERS = (
        'XMLHttpRequest',
        'X_FILENAME',
        'accept-encoding',
        'authorization',
        'content-type',
        'dnt',
        'origin',
        'user-agent',
        'x-csrftoken',
        'x-requested-with',
    )

    前端部分

    羊驼类型组件调整的时候, 会在页面渲染前来进行axios 请求数据

    <template>
      <div>羊驼类型 ID={{id}}</div>
    </template>
    
    <script>
      export default {
        name: "MemberType",
        props: ["id"],
        beforeRouteEnter: (to, from, next) => {
          next(vm => {
            vm.getData()
          })
        },
        beforeRouteLeave: (to, from, next) => {
        },
        methods: {
          getData: function () {
            this.axios({
              method: 'get',
              url: 'http://127.0.0.1:8000/yangtuo/type/',
            }).then(function (repos) {
              console.log(repos)
            }).catch(function (error) {
              console.log(error)
            })
    
          }
        }
      }
    </script>
    
    <style scoped>
    
    </style>

    可以看到请求到的数据就在这里打印出来了

    Vuex 解决状态问题

    Vuex 是 vue 中的状态管理控制器, 用于集中管理所有组件的状态,

    安装使用

    cnpm install vuex --save

    main.js 

    import Vuex from 'vuex'
    Vue.use(Vuex)

    应用场景

    比如登录态的判断, 如果没登录访问任何页面都跳转到登录页进行登录

    场景实现

    基于 sessionStorage 

    首先, login的组件里面在登录成功之后在 session 里面设定一个 登录标识

          submitForm(formName) {
            this.$refs[formName].validate((valid) => {
              if (valid) {
                sessionStorage.setItem('isLogin', 'true')
                this.$router.push({name: "Main", params: {username: this.form.name}})
              } else {
                this.$message({
                  message: '用户名或者密码未填',
                  type: 'warning'
                });
                return false;
              }
            });
          },

    然后, 在main.js 里面调用钩子函数 beforeEach

    相关的代码, 因为需要全局生效. 所以在 main.js 中

    // 路由跳转前
    router.beforeEach((to, from, next) => {
      let isLogin = sessionStorage.getItem('isLogin')
      console.log(isLogin)
      console.log(to.path)
      // 登出,
      if (to.path == '/logout') {
        // 清理状态
        sessionStorage.clear();
        // 跳转登录页
        next({path: '/login/'});
        // 登录
      } else if (to.path == '/login') {
        // 是否已登录
        if (isLogin != null) {
          next({path: '/main'});
        }
      } else if (isLogin == null) {
        next({path: '/login'});
      }
      next()
    })

    基于 Vuex

    sessionStroage 只能简单的存储一些键值对, 而实际用户对象的存储则不方便

    使用 Vuex 即可解决这个问题

    配置

    在 src 根目录下创建一个 store 文件来保存 Vuex 的配置文件 index.js 内容如下

    import Vue from "vue"
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    
    // 全局的 state 对象, 用于保存所有组件的公共数据
    const state = {
      user: {
        name: ""
      }
    }
    
    // 监听state 对象的值的最新状态 (计算属性)
    const getters = {
      getUser(state) {
        return state.user
      }
    }
    
    // 唯一一个可以修改 state 值得方法 (同步执行)
    const mutations = {
      updateUser(state, user) {
        state.user = user
      }
    }
    
    // 异步执行 mutations 方法
    const actions = {
      asyncUpdateUser(context, user) {
        context.commit("updateUser", user)
    
      }
    }
    
    
    export default new Vuex.Store({
      state,
      getters,
      mutations,
      actions
    })

    注册

    main.js 里面进行注册

    import store from "./store";
    
    
    new Vue({
      el: '#app',
      router,
      store,
      components: {App},
      template: '<App/>',
      render: h => h(App)
    })

    使用

    login 组件里面当登录成功时, 可以调用 dispatch 方法去调用 异步更新 state 里面的 user 对象

          submitForm(formName) {
            this.$refs[formName].validate((valid) => {
              if (valid) {
                sessionStorage.setItem('isLogin', '');
                this.$store.dispatch('asyncUpdateUser', {name: this.form.name})
                this.$router.push({name: "Main", params: {username: this.form.name}});
              } else {
                this.$message({
                  message: '用户名或者密码未填',
                  type: 'warning'
                });
                return false;
              }
            });
          },

    state 的内容使用

     <span>{{$store.getters.getUser.name}}</span>

    效果示例

    登录成功后 右上角的这个登录用户的显示可以直接在 state 里面去取

    刷新重置问题处理

    但是目前存在一个问题, 就是刷新之后就没有了, 目前的示例都是在一个单页面上进行

    每次刷新之后, state 就会恢复默认值

    解决思路

    可以监听刷新动作的发生, 然后一旦刷新就保存当前的 state 信息进 sessionStorage 中

    以及 state 生成的时候页判断下 sessionStorage 中是不是已存在. 存在直接用即可

    App.vue 里面加这两个

    mounted() {
          window.addEventListener('unload', this.saveState);
        },
        methods: {
          saveState() {
            sessionStorage.setItem('state', JSON.stringify(this.$store.state));
          }
        }

    声明的地方这样调整即可

    const state = sessionStorage.getItem('state') ? JSON.parse(sessionStorage.getItem('state')) : {
      user: {
        name: ""
      }
    }

    模板化

    上述的示例是个单文件应用, 只用了一个 user 状态

    如果存在很多的时候, 最好每个状态都分别用一个文件区分开. 进行模板化处理

    以上示例进行封装的形式如下

     在 store里面建立 modules 的文件夹下, 对 user 单独起一个 js

    user.js 

    内容的变化就是放进了对象里面, 要做一些调整, 并且暴露出去

    const user = {
    // 全局的 state 对象, 用于保存所有组件的公共数据
      state : sessionStorage.getItem('state') ? JSON.parse(sessionStorage.getItem('state')) : {
        user: {
          name: ""
        }
      },
    
    // 监听state 对象的值的最新状态 (计算属性)
      getters : {
        getUser(state) {
          return state.user
        }
      },
    
    // 唯一一个可以修改 state 值得方法 (同步执行)
      mutations : {
        updateUser(state, user) {
          state.user = user
        }
      },
    
    // 异步执行 mutations 方法
      actions : {
        asyncUpdateUser(context, user) {
          context.commit("updateUser", user)
    
        }
      }
    }
    
    export default user

    index.js

    这里则需要对暴露出去的 user 进行引用

    import Vue from "vue"
    import Vuex from 'vuex'
    import user from "./modules/user";
    Vue.use(Vuex)
    
    
    
    
    export default new Vuex.Store({
      modules: {
        user
      }
    })

    使用上没有变化

    只有原生使用的时候需要调整到 去 user 对象中, (为解决刷新问题的时候使用的)

    之前是直接存进去的是 state 中, 现在是放在 user 里面了. 

    App.vue

    <template>
      <div id="app">
        <router-view/>
      </div>
    </template>
    
    <script>
      export default {
        name: 'App',
        mounted() {
          window.addEventListener('unload', this.saveState);
        },
        methods: {
          saveState() {
            
            // sessionStorage.setItem('state', JSON.stringify(this.$store.state)); 
            sessionStorage.setItem('state', JSON.stringify(this.$store.state.user));
          }
        }
      }
    </script>
    
    <style>
    
    </style>

    --------------------orz 竣工

  • 相关阅读:
    函数終探------匿名函数
    再探函数2---函数的嵌套与装饰器
    无需触摸芯片的触摸电路
    单芯片移动电源方案——1A同步升压5V--TP4351B
    HTML列表元素
    HTML表格元素
    HTML基本元素
    创建HTML5文档
    HTML5环境安装
    windows本地搭建https环境,tomcat使用https协议
  • 原文地址:https://www.cnblogs.com/shijieli/p/14905672.html
Copyright © 2020-2023  润新知