vue3的学习--结合和整理了几个人的博客,主要自学

本文探讨了Vue3中全局属性的替代、store使用对比、路由router升级,以及setup函数的运用。还涵盖了axios封装、Vue路由详解、动态路由权限控制和Vuex状态管理。重点介绍了响应式API(ref和reactive)及Element Plus的集成和跨域处理。
摘要由CSDN通过智能技术生成

1、全局属性

vue2:
对于一些第三方插件,vue2中通常使用prototype原型来挂载到vue对象中

import Vue from 'vue'
Vue.prototype.$http=Axiox
Vue.prototype.$echart= Echart

vue3:
vue3中提供了一个名为globalProperties的全局属性配置,可以代替vue2

app.config.globalProperties.$http = Axios
app.config.globalProperties.$echart = Echart

2、main.js对比在这里插入图片描述

3、store的使用对比

在这里插入图片描述

4、路由router的使用对比

在这里插入图片描述

5、Vue3生命周期变化以及setup函数

与 2.x 版本生命周期相对应的组合式 API

1.beforeCreate -> 使用 setup()
2.created -> 使用 setup()
3.beforeMount -> onBeforeMount
4.mounted -> onMounted
5.beforeUpdate -> onBeforeUpdate
6.updated -> onUpdated
7.beforeDestroy -> onBeforeUnmount
8.destroyed -> onUnmounted
9.errorCaptured -> onErrorCaptured

beforeCreate和created会在setup中执行
无法使用this拿到当前组件的相关数据 setup只能同步执行,不可以异步

6、ref,reactive响应式api

被响应式api标记过的数据才可以成为响应式数据
ref–用来标记简单类型数据
reactive—标记复杂类型数据(深度响应式)

如果用ref对象/数组, 会自动将对象/数组转换为reactive的代理对象
ref的数据操作: 在js中要.value, 在模板中不需要(内部解析会自动添加.value)
在这里插入图片描述

7、Element-plus引入

使用cli安装 vue add element-plus
官网路径: https://element-plus.gitee.io/#/zh-CN

8、引入http请求框架axios

安装 axios http请求框架 npm install axios
axios基础使用方法:
axios.create({config}) //创建axios实例
axios.get(url,{config}) //get请求
axios.post(url, data,{config}) //post请求
axios.interceptors.request.use() // 请求拦截器
axios.interceptors.response.use() // 请求拦截器

封装后的axios

import axios from 'axios'
//axios.create 创建一个axios实例  我们给这个实例编写配置,后续所有通过实例发送的请求,都受当前配置约束
const $http = axios.create({
    baseURL: '',
    timeout: 1000,
    // headers: {'X-Custom-Header': 'foobar'}
  });
 
  // 添加请求拦截器
  $http.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    config.headers.token='123123123'
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });
 
// 添加响应拦截器
$http.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    let data=response.data;
    
    return data;
  }, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  });
 
  export default $http

http/api.js

import $http from './index.js'
 
export const getCourseList= (data)=>{
    return $http.get('http://jsonplaceholder.typicode.com/posts',data)
}
 
export const login=(data)=>{
    return $http.post('http://jsonplaceholder.typicode.com/posts',data)
}

login.vue

<template>
  <div class="login">
    <h4>朝夕后台管理系统</h4>
    <el-form
      label-width="80px"
      :model="loginData"
    >
      <el-form-item label="账号">
        <el-input placeholder="请输入账号" v-model="loginData.name"></el-input>
      </el-form-item>
      <el-form-item label="密码">
        <el-input placeholder="请输入密码" v-model="loginData.password" show-password></el-input>
      </el-form-item>
       <el-form-item>
          <el-button @click="subFun" class="sub-btn" type="primary">登录</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
import {reactive } from 'vue'
 import { ElMessage } from 'element-plus'
 import {login} from '../http/api.js'
 import router from '../router/index.js'
export default {
  name: "Login",
  setup() {
      let loginData=reactive({
        name:'',
        password:''
      })
 
      let subFun =()=>{
        //先判断账号密码是否已经填写
          if(!loginData.name||!loginData.password){
              ElMessage.error('请先填写账号和密码');
              return
          }
 
          login(loginData).then(res=>{
            console.log(res)
            router.push('/Home')
          })
 
      }
      return{
        loginData,
        subFun
      }
  },
};
</script>
<style scoped>
.login{
  width: 500px;
  margin: 150px auto;
  border:1px solid #efefef;
  border-radius: 10px;
  padding:20px
}
h4{
  text-align: center;
}
.sub-btn{
  width: 100%;
}
</style>

9、axios跨域处理

①项目根目录创建vue.config.js

②写入devServe配置

③解析devServe配置
在这里插入图片描述

10、Vue路由

路由模式
1、 Hash模式 通过 URL 的 hash 来模拟一个完整的 URL于是当 URL 改变时,页面不会重新加载
2、History模式 利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 修改浏览器的历史记录栈

动态路由

路由传参
1.通过 标签

<router-link :to="{name:xxx,params:{key:value}}">valueString</router-link> //$route.params.key

2.url传参

path:'/params/:newsId/:newsTitle', //$route.params.newsId

3.query传参

{ name:'xxx',query: { queryId: status }} //$route.query.queryId

路由跳转方式
1、<ruter-link/>

1. 不带参数
<router-link :to="{name:'home'}"> 
<router-link :to="{path:'/home'}"> //name,path都行, 建议用name  
// 注意:router-link中链接如果是'/'开始就是从根路由开始,如果开始不带'/',则从当前路由开始。
**router-link 不带参数 path中不加/表示相对路径,还得加一个append属性才能跳转到相对路径**

2.带参数
<router-link :to="{name:'home', params: {id:1}}">  
// params传参数 (类似post)
// 路由配置 path: "/home/:id" 或者 path: "/home:id" 
// 不配置path ,第一次可请求,刷新页面id会消失
// 配置path,刷新页面id会保留
 
// html 取参  $route.params.id
// script 取参  this.$route.params.id
 
<router-link :to="{name:'home', query: {id:1}}"> 
 
// query传参数 (类似get,url后面会显示参数)
// 路由可不配置
 
// html 取参  $route.query.id
// script 取参  this.$route.query.id

2、this.$router.push() (函数里面调用)

1.  不带参数
 
this.$router.push('/home')
this.$router.push({name:'home'})
this.$router.push({path:'/home'})
 
2. query传参 
this.$router.push({name:'home',query: {id:'1'}})
this.$router.push({path:'/home',query: {id:'1'}})
 
// html 取参  $route.query.id
// script 取参  this.$route.query.id
 
3. params传参
this.$router.push({name:'home',params: {id:'1'}})  // 只能用 name
// 路由配置 path: "/home/:id" 或者 path: "/home:id" ,
// 不配置path ,第一次可请求,刷新页面id会消失
// 配置path,刷新页面id会保留
 
// html 取参  $route.params.id
// script 取参  this.$route.params.id
 
4. query和params区别
query类似 get, 跳转之后页面 url后面会拼接参数,类似?id=1, 非重要性的可以这样传, 密码之类还是用params刷新页面id还在
 
params类似 post, 跳转之后页面 url后面不会拼接参数 , 但是刷新页面id 会消失

3、 this.$router.replace()(用法同上,push)
4、 this.$router.go(n)

this.$router.go(n)
向前或者向后跳转n个页面,n可为正整数或负整数

ps : 区别
this.$router.push
跳转到指定url路径,并想history栈中添加一个记录,点击后退会返回到上一个页面
this.$router.replace
跳转到指定url路径,但是history栈中不会有记录,点击返回会跳转到上上个页面 (就是直接替换了当前页面)
this.$router.go(n)
向前或者向后跳转n个页面,n可为正整数或负整数

十一、动态路由(角色权限为例子)

1、通过动态添加路由和菜单显示来控制,不能访问的页面不添加到路由表和菜单表里面。
2、所有页面都展示,但是访问的时候做下判断限制,如果是没有权限的角色访问,跳转到404页面。

思路:
在每一个路由的 meta 属性里,将能访问该路由的角色添加到 roles 里。用户每次登陆后,将用户的角色返回。然后在访问页面时,把路由的 meta 属性和用户的角色进行对比,如果用户的角色在路由的 roles 里,那就是能访问,如果不在就拒绝访问。

路由信息

routes: [
    {
        path: '/login',
        name: 'login',
        meta: {
            roles: ['admin', 'user']
        },
        component: () => import('../components/Login.vue')
    },
    {
        path: 'home',
        name: 'home',
        meta: {
            roles: ['admin']
        },
        component: () => import('../views/Home.vue')
    },
]

页面控制

// 假设角色有两种:admin 和 user
// 这里是从后台获取的用户角色
const role = 'user'
// 在进入一个页面前会触发 router.beforeEach 事件
router.beforeEach((to, from, next) => {
    if (to.meta.roles.includes(role)) {
        next()
    } else {
        next({path: '/404'})
    }
})

通过token验证登录语法

router.beforeEach((to, from, next) => {
    // 如果有token 说明该用户已登陆
    if (localStorage.getItem('token')) {
        // 在已登陆的情况下访问登陆页会重定向到首页
        if (to.path === '/login') {
            next({path: '/'})
        } else {
            next({path: to.path || '/'})
        }
    } else {
        // 没有登陆则访问任何页面都重定向到登陆页
        if (to.path === '/login') {
            next()
        } else {
            next(`/login?redirect=${to.path}`)
        }
    }
})

动态生成路由
利用 vue-router 的 addRoutes 方法可以动态添加路由

router.addRoutes(routes: Array<RouteConfig>)

动态添加更多的路由规则。参数必须是一个符合 routes 选项要求的数组。
routes数组示例:

const router = new Router({
    routes: [
        {
            path: '/login',
            name: 'login',
            component: () => import('../components/Login.vue')
        },
        {path: '/', redirect: '/home'},
    ]   
})

上面的代码和下面的代码效果是一样的

const router = new Router({
    routes: [
        {path: '/', redirect: '/home'},
    ]   
})

router.addRoutes([
    {
        path: '/login',
        name: 'login',
        component: () => import('../components/Login.vue')
    }
])

在动态添加路由的过程中,如果有 404 页面,一定要放在最后添加,否则在登陆的时候添加完页面会重定向到 404 页面。

类似于这样,这种规则一定要最后添加。

{path: '*', redirect: '/404'}

假设后台数据menu

// 左侧菜单栏数据
menuItems: [
    {
        name: 'home', // 要跳转的路由名称 不是路径
        size: 18, // icon大小
        type: 'md-home', // icon类型
        text: '主页' // 文本内容
    },
    {
        text: '二级菜单',
        type: 'ios-paper',
        children: [
            {
                type: 'ios-grid',
                name: 't1',
                text: '表格'
            },
            {
                text: '三级菜单',
                type: 'ios-paper',
                children: [
                    {
                        type: 'ios-notifications-outline',
                        name: 'msg',
                        text: '查看消息'
                    },
                    {
                        type: 'md-lock',
                        name: 'password',
                        text: '修改密码'
                    },
                    {
                        type: 'md-person',
                        name: 'userinfo',
                        text: '基本资料',
                    }
                ]
            }
        ]
    }
]

示例菜单栏,可以参考iview组件或者elementUI-plus版本的组件

<!-- 菜单栏 -->
<Menu ref="asideMenu" theme="dark" width="100%" @on-select="gotoPage" 
accordion :open-names="openMenus" :active-name="currentPage" @on-open-change="menuChange">
    <!-- 动态菜单 -->
    <div v-for="(item, index) in menuItems" :key="index">
        <Submenu v-if="item.children" :name="index">
            <template slot="title">
                <Icon :size="item.size" :type="item.type"/>
                <span v-show="isShowAsideTitle">{{item.text}}</span>
            </template>
            <div v-for="(subItem, i) in item.children" :key="index + i">
                <Submenu v-if="subItem.children" :name="index + '-' + i">
                    <template slot="title">
                        <Icon :size="subItem.size" :type="subItem.type"/>
                        <span v-show="isShowAsideTitle">{{subItem.text}}</span>
                    </template>
                    <MenuItem class="menu-level-3" v-for="(threeItem, k) in subItem.children" :name="threeItem.name" :key="index + i + k">
                        <Icon :size="threeItem.size" :type="threeItem.type"/>
                        <span v-show="isShowAsideTitle">{{threeItem.text}}</span>
                    </MenuItem>
                </Submenu>
                <MenuItem v-else v-show="isShowAsideTitle" :name="subItem.name">
                    <Icon :size="subItem.size" :type="subItem.type"/>
                    <span v-show="isShowAsideTitle">{{subItem.text}}</span>
                </MenuItem>
            </div>
        </Submenu>
        <MenuItem v-else :name="item.name">
            <Icon :size="item.size" :type="item.type" />
            <span v-show="isShowAsideTitle">{{item.text}}</span>
        </MenuItem>
    </div>
</Menu>

其实就是通过三次 v-for 不停的对子数组进行循环,生成三级菜单。
基础动态路由

const asyncRoutes = {
    'home': {
        path: 'home',
        name: 'home',
        component: () => import('../views/Home.vue')
    },
    't1': {
        path: 't1',
        name: 't1',
        component: () => import('../views/T1.vue')
    },
    'password': {
        path: 'password',
        name: 'password',
        component: () => import('../views/Password.vue')
    },
    'msg': {
        path: 'msg',
        name: 'msg',
        component: () => import('../views/Msg.vue')
    },
    'userinfo': {
        path: 'userinfo',
        name: 'userinfo',
        component: () => import('../views/UserInfo.vue')
    }
}

// 传入后台数据 生成路由表
menusToRoutes(menusData)

// 将菜单信息转成对应的路由信息 动态添加
function menusToRoutes(data) {
    const result = []
    const children = []

    result.push({
        path: '/',
        component: () => import('../components/Index.vue'),
        children,
    })

    data.forEach(item => {
        generateRoutes(children, item)
    })

    children.push({
        path: 'error',
        name: 'error',
        component: () => import('../components/Error.vue')
    })

    // 最后添加404页面 否则会在登陆成功后跳到404页面
    result.push(
        {path: '*', redirect: '/error'},
    )

    return result
}

function generateRoutes(children, item) {
    if (item.name) {
        children.push(asyncRoutes[item.name])
    } else if (item.children) {
        item.children.forEach(e => {
            generateRoutes(children, e)
        })
    }
}

动态路由的其他配置信息链接

十二、vuex全局状态

Vuex 数据操作流程

1.state 应用层级的状态应该集中到单个 store 对象中

  1. mutation 更改状态的唯一方法,并且这个过程是同步的

  2. action 异步逻辑都应该封装到 action 里面

属性存储

vue2

export default {
  props: {
    title: String
  },
  data () {
    return {
      username: '',
      password: ''
    }
  }
}

vue3
新的setup()方法,此方法在组件初始化构造的时候触发

ref与v-for一起运用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值