vue pc项目 router.js 配置详解 ,vue项目中路由懒加载的正确使用,vue实现动态路由一步到位

news2025/2/25 3:41:11

这个是我之前一个项目的router.js 文件
xmjd

import Vue from 'vue'
import http from './plugins/axios'
import Router from 'vue-router'
import { getChnPinyin } from "@/utils/chnpinyin";
import { clearLoginInfo, handlerMenu } from '@/utils'

Vue.use(Router)
// 解决ElementUI导航栏中的vue-router在3.0版本以上重复点菜单报错问题
const originalPush = Router.prototype.push
Router.prototype.push = function push(location) {
  return originalPush.call(this, location).catch(err => err)
}

// 开发环境不使用懒加载, 因为懒加载页面太多的话会造成webpack热更新太慢, 所以只有生产环境使用懒加载
const _import = require('./import-' + process.env.NODE_ENV)

/**
 * 全局路由
 */
const globalRoutes = [
  {
    path: '/login',
    name: 'login',
    meta: {
      title: "登录",
    },
    isHide: true,
    component: () => import(/* webpackChunkName: 'login' */ "./views/login")
  },
  {
    path: '/404',
    name: "404",
    isHide: true,
    component: () => import("./views/404")
  }
]

// 主入口路由(需嵌套上左右整体布局)
const mainRoutes = [{
  path: '/',
  name: 'main',
  meta: {
    title: "主页",
  },
  redirect: { name: 'home' },
  component: () => import(/* webpackChunkName: 'main' */ './views/main'),
  children: [
    {
      path: "/home",
      name: "home",
      meta: {
        title: "主页",
        icon: "fa-zhuye"
      },
      component: () => import(/* webpackChunkName: 'main' */ './views/home')
    },
    {
      path: "/userinfo",
      name: "userinfo",
      meta: {
        title: "用户信息"
      },
      isHide: true,
      component: () => import(/* webpackChunkName: 'user' */ "./views/modules/user"),
      children: [
        {
          path: "profile",
          name: "profile",
          meta: {
            title: "基本信息"
          },
          component: () => import(/* webpackChunkName: 'userprofile' */ "./views/modules/user/profile")
        },
        {
          path: "pwmanage",
          name: "pwmanage",
          meta: {
            title: "修改密码"
          },
          component: () => import(/* webpackChunkName: 'userpwmanage' */ "./views/modules/user/pwmanage")
        },
      ]
    },
    {
      path: '/wsview',
      name: 'wsview',
      meta: {
        title: "查看文书",
        icon: "fa-zhuye"
      },
      isHide: true,
      component: () => import(/* webpackChunkName: 'wsviewer' */ "./views/wsviewer")
    },
    {
      path: "/yuejuan",
      name: "yuejuan",
      meta: {
        title: "阅卷",
      },
      isHide: true,
      component: () => import(/* webpackChunkName: 'yuejuan' */ "./views/yuejuan")
    }
  ],
  beforeEnter(to, from, next) {
    let token = ''
    if (window.top == window.self) {
      token = Vue.cookie.get('token')
    } else if (window.top !== window.self) {
      token = window.localStorage.getItem("token")
    } else {
      token = window.localStorage.getItem("token")
    }
    if (!token || !/\S/.test(token)) {
      clearLoginInfo()
      next({ name: 'login' })
    }
    next()
  }
}]


/**
 * 判断当前路由类型, global: 全局路由, main: 主入口路由
 * @param {*} route 当前路由
 */
function fnCurrentRouteType(route, globalRoutes = []) {
  let temp = []
  for (let i = 0; i < globalRoutes.length; i++) {
    if (route.name === globalRoutes[i].name/* route.path === globalRoutes[i].path */) {
      return 'global'
    } else if (globalRoutes[i].children && globalRoutes[i].children.length >= 1) {
      temp = temp.concat(globalRoutes[i].children)
    }
  }
  return temp.length >= 1 ? fnCurrentRouteType(route, temp) : 'main'
}

const router = new Router({
  mode: 'history',
  scrollBehavior: () => ({ y: 0 }),
  base: process.env.BASE_URL,
  routes: globalRoutes.concat(mainRoutes)
})

router.beforeEach((to, from, next) => {
  console.log(to, from, next)
  if (router.options.isAddDynamicMenuRoutes || fnCurrentRouteType(to, globalRoutes) === 'global') {
    next()
  } else {
    http({
      url: '/sys/menu/nav',
      method: 'get',
      notip: true,
    }).then(({ data }) => {
      console.log(data);
      if (data.code == "0000" || data.code == "0") {
        var dat = data;
        var nlist = handlerMenu(dat.menuList)
        console.log(nlist)
        //先清除路由再动态添加
        resetRouter();
        fnAddDynamicMenuRoutes(nlist, [])
        router.options.isAddDynamicMenuRoutes = true
        sessionStorage.setItem('menuList', JSON.stringify(nlist || '[]'))
        sessionStorage.setItem('permissions', JSON.stringify(dat.permissions || '[]'))
        sessionStorage.setItem('dictList', JSON.stringify(dat.dictList || '[]'))
        sessionStorage.setItem('orgList', JSON.stringify(dat.orgList || '[]'))
        sessionStorage.setItem('userList', JSON.stringify(dat.userList || '[]'))
        router.replace(to)
      } else {
        sessionStorage.setItem('menuList', '[]')
        sessionStorage.setItem('permissions', '[]')
        sessionStorage.setItem('dictList', '[]')
        sessionStorage.setItem('orgList', '[]')
        sessionStorage.setItem('userList', '[]')
        next()
      }
    }).catch((e) => {
      console.error(e);
      console.log(`%c${e} 请求菜单列表和权限失败,跳转至登录页!!`, 'color:blue')
      // router.push({ name: 'login' })
      // router.replace({path:"/login"});
      // setTimeout(()=>{
      //   location.reload();
      // },200)
    })
  }
})

function resetRouter() {
  const newRouter = new Router({
    mode: 'history',
    scrollBehavior: () => ({ y: 0 }),
    base: process.env.BASE_URL,
    routes: globalRoutes.concat(mainRoutes)
  });
  router.matcher = newRouter.matcher; // reset router
}

function diguiAddMenu(list, pid) {
  for (let i = 0; i < list.length; i++) {
    let v = list[i];
    v.meta = {
      title: v.name,
      icon: v.icon,
      isDynamic: true,
      menuId: v.menuId,
      fg: v.fg,
      datasource: v.datasource,
      compareModuleId: v.compareModuleId,
      blockColorParams: v.blockColorParams ? JSON.parse(v.blockColorParams) : []
    }
    v.title = v.name;
    if (v.url) {
      v.path = v.url.split("/").pop();
      v.name = v.url.split("/").pop();
    } else {
      v.path = getChnPinyin(v.name);
      v.name = getChnPinyin(v.name);
    }
    console.log(v.url);
    v.component = () => import(/* webpackChunkName: 'jumpper' */ "./views/jump");
    if (!v.datasource || v.datasource == "local") {
      // obj.realComponent = _import("modules/"+(v.url.indexOf("sys")>-1?v.url:v.url+"/index"));
      v.realComponent = v.url ? ("modules/" + (v.url + "/index")) : "modules/common/index";
    }

    if (v.list) {
      v.children = v.list;
      diguiAddMenu(v.list);
    }
  }
}

function fnAddDynamicMenuRoutes(menuList = [], routes = []) {
  diguiAddMenu(menuList);
  for (let i = 0; i < menuList.length; i++) {
    if (menuList[i].children && menuList[i].children[0]) {
      menuList[i].redirect = { name: menuList[i].children[0].name }
    }
    routes.push(menuList[i]);
  }
  mainRoutes[0].children = mainRoutes[0].children.concat(routes);

  console.log(router);
  router.addRoutes([
    mainRoutes[0],
    { path: '*', redirect: { name: '404' } }
  ])
  console.log(mainRoutes)
}


export default router;

路由懒加载:
使用() => import();的方式导入组件
这样可以在进入当前路由的时候加载路由
如果不使用懒加载 会在第一次进入页面后 一次性加载所有路由 所以首屏加载会慢

如果一个项目过大 大量的使用路由懒加载会导致页面的热更新过慢
推荐在开发环境下不使用懒加载 这样有利于开发的效率
在生产环境可以使用路由懒加载

通过process.env.NODE_ENV可以访问到当前是什么环境
可以在utils文件夹下创建两个文件
util.import.development.js文件里是开发环境的导入方式

// file : 传入的文件名 和view拼接成路径
// 开发环境不需要使用懒加载  只要正常方式引入文件
module.exports = file => require('@/views/' + file).default;

util.import.production.js文件里一个是生产环境的导入方式

// file : 传入的文件名 和view拼接成路径
// 生产环境使用懒加载
module.exports = file => () => import('@/views/' + file);

然后在导入路由的时候

// 根据process.env.NODE_ENV的字段拼接路径
const _import = require('@/util.import.' + process.env.NODE_ENV);

 }
    path: 'index',
    name: 'index',
    meta: {
      title: '首页',
    },
    component: _import('system/index') // 传入文件名即可使用导入
  },

xmjd就是
最近在写vue项目,需要由后台传来当前用户对应权限的路由表,前端通过调接口拿到后处理(后端处理路由),就是配置vue动态路由啦。

由于错信了一些网上的文章:(,导致在这个问题上耗费了不少时间,想想,还是自己写一篇文章来记录一下那些遇到的坑吧。

接下来手把手记录一下,如何从零开始配置vue动态路由。

首先呢,先看看静态路由的配置,简单预览一下,熟悉的可以直接跳过,说这部分,是为了熟悉一下路由的配置,配置动态路由其实就是把静态路由存到数据库,在取出来放进路由表(静态是直接写在路由表里)。
静态路由的回顾
1.创建router/index.js文件,这里只有一些简单的页面

import Vue from 'vue'
import Router from 'vue-router'
import Login from '@/view/login/Login'
import Index from '@/layout/Index'
import Welcome from '@/layout/welcome/Welcome'
 
Vue.use(Router)
 
export default new Router({
  routes: [
    {
      path: '/login',
      name: 'Login',
      component: Login
    },
    {
      path: '/',
      component: Index,
      redirect: '/welcome',
      meta: {requireAuth: true},
      children: [
        {
          path: '/welcome',
          component: Welcome,
          name: '首页',
          meta: {title: '首页', requireAuth: true}
        }
      ]
    }
  ]
})

2.创建router/permission.js文件,配置导航守卫,可以在每次路由跳转前做一些操作,待会获取动态路由操作也在这里配置

import router from '@/router/index'
import 'element-ui/lib/theme-chalk/index.css'
import '@fortawesome/fontawesome-free/css/all.min.css'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
 
NProgress.configure({
  easing: 'ease', // 动画方式
  speed: 500, // 递增进度条的速度
  showSpinner: false, // 是否显示加载ico
  trickleSpeed: 200, // 自动递增间隔
  minimum: 0.3 // 初始化时的最小百分比
})
// 白名单
const whiteList = ['/login'] // no redirect whitelist
 
// 导航守卫
router.beforeEach((to, from, next) => {
  NProgress.start()
  if (to.meta.requireAuth) {
    // 判断该路由是否需要登录权限
    if (sessionStorage.getItem('loginName') !== null) {
      // 判断本地是否存在token
      next()
      // 这里是待会获取异步路由的地方
    } else {
      // 未登录,跳转到登陆页面
      next({
        path: '/login'
      })
    }
  } else {
    if (whiteList.indexOf(to.path) !== -1) {
      next()
    } else {
      if (sessionStorage.getItem('loginName') !== null) {
        // 判断本地是否存在token
        next(`/?redirect=${to.path}`)
      } else {
        next(`/login?redirect=${to.path}`)
      }
    }
  }
})
 
router.afterEach(() => {
  // 在即将进入新的页面组件前,关闭掉进度条
  NProgress.done()
})

这里引用了一个插件,Nprogress,就是下图的蓝色小进度条。不用也可以
在这里插入图片描述
3.在main.js里引入刚才创建的router下的index.js文件和permission.js文件,如下

import router from '@/router'
import './router/permission'
 
new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

4.在App入口中放入路由跳转的视图区,跳转的路由页面都显示在这里

// APP.vue文件
<div id="app">
    <router-view />
</div>

现在静态路由就配好了,可以正常的跳转了!

文件夹长这样
在这里插入图片描述
动态路由的配置
接下来开始配置动态路由了!

有坑的地方我会说明一下。

1.首先呢,router/index.js,没有什么需要改的,把你需要动态获取的路由信息删除掉即可,可以留一部分静态路由,如登录页,首页等等,若全删,routes赋为[]即可。

2.创建一个文件,我命名为getAsyncRouter.js,用来处理获取到的动态路由信息。

// 用于处理动态菜单数据,将其转为 route 形式
export function fnAddDynamicMenuRoutes (menuList = [], routes = []) {
  // 用于保存普通路由数据
  let temp = []
  // 用于保存存在子路由的路由数据
  let route = []
  // 遍历数据
  for (let i = 0; i < menuList.length; i++) {
    // 存在子路由,则递归遍历,并返回数据作为 children 保存
    if (menuList[i].children && menuList[i].children.length > 0) {
      // 获取路由的基本格式
      route = getRoute(menuList[i])
      // 递归处理子路由数据,并返回,将其作为路由的 children 保存
      route.children = fnAddDynamicMenuRoutes(menuList[i].children)
      // 保存存在子路由的路由
      routes.push(route)
    } else {
      // 保存普通路由
      temp.push(getRoute(menuList[i]))
    }
  }
  // 返回路由结果
  return routes.concat(temp)
}
 
// 返回路由的基本格式
function getRoute (item) {
  // 路由基本格式
  let route = {
    // 路由的路径
    path: item.url,
    // 路由名
    name: item.name,
    // 路由所在组件
    // component: (resolve) => require([`@/layout/Index`], resolve),
    component: (resolve) => require([`@/view${item.curl}`], resolve),
    meta: {
      id: item.id,
      icon: item.icon
    },
    // 路由的子路由
    children: []
  }
  // 返回 route
  return route
}

这里是两个函数,把获取到的数据处理成路由表数据,将其变化成 route 的形式。

fnAddDynamicMenuRoutes 用于递归菜单数据。
getRoute 用于返回某个数据转换的 路由格式。
注释写的应该算是很详细了,主要讲一下思路:
  对数据进行遍历,
  定义两个数组(temp,route),temp 用于保存没有子路由的路由,route 用于保存存在子路由的路由。
  如果某个数据存在 子路由,则对子路由进行遍历,并将其返回结果作为当前数据的 children。并使用 route 保存路由。
  如果某个数据不存在子路由,则直接使用 temp 保存路由。
  最后,返回两者拼接的结果,即为转换后的数据。
route 格式一般如下:
  path:指路由路径(可以根据路径定位路由)。
  name:指路由名(可以根据路由名定位路由)。
  component:指路由所在的组件。
  children:指的是路由组件中嵌套的子路由。
  meta:用于定义路由的一些元信息。

这里有个大坑!!! 在配置component的时候,需要动态导入组件,也就是vue异步组件,查看文档如下
在这里插入图片描述
可知,有两种导入方式,import和require方式。这里简单说一下,

1 import属于es6导入方式,只支持静态导入,也就是说,你不能够使用变量或表达式,只能使用字符串。

2 require属于commonJS方式,可以支持动态的导入,但笔者尝试中,可以使用``模板字符串方式,貌似也无法直接使用变量。这里尽量用字符串拼接,而不是用变量去代替拼接的字符串!

由于import不支持动态导入方式,笔者采用的是require的方式,并且在webpack文档中有这样一段话。
在这里插入图片描述
综上所述,就是说,组件的导入可以使用字符串拼接的方式导入,可以使用模板字符串导入(字符串中含有变量),但是使用模板字符串导入时不能够只使用变量!!必须指定一个目录,不能全用变量代替!

// 字符串拼接方式
component: import('@/view'+'/sys/user')
// 模板字符串方式,webpack4+版本需使用require方式,注意,`@${item.curl}`,是不行的!必须指定一个目录,不能全用变量代替
component: (resolve) => require([`@/view${item.curl}`], resolve),

这个现象其实是与webpack import()的实现高度相关的。由于webpack需要将所有import()的模块都进行单独打包,所以在工程打包阶段,webpack会进行依赖收集。

此时,webpack会找到所有import()的调用,将传入的参数处理成一个正则,如:

import('./app'+path+'/util') => /^\.\/app.*\/util$/

也就是说,import参数中的所有变量,都会被替换为【.*】,而webpack就根据这个正则,查找所有符合条件的包,将其作为package进行打包。

所以动态导入的正确姿势,应该是尽可能静态化表达包所处的路径,最小化变量控制的区域。

3.有了处理动态路由数据的函数,那就需要在合适的地方调用,以发挥作用。这时就需要用到beforeEach了,在router/permission.js文件,配置导航守卫,可以在每次路由跳转前做一些操作,这里就是获取动态路由了

import router from '@/router/index'
import 'element-ui/lib/theme-chalk/index.css'
import '@fortawesome/fontawesome-free/css/all.min.css'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import {fnAddDynamicMenuRoutes} from '@/router/getAsyncRouter'
import {getRouter} from '@/api/sys/Menu'
import store from '@/store'
 
 
NProgress.configure({
  easing: 'ease', // 动画方式
  speed: 500, // 递增进度条的速度
  showSpinner: false, // 是否显示加载ico
  trickleSpeed: 200, // 自动递增间隔
  minimum: 0.3 // 初始化时的最小百分比
})
// 白名单
const whiteList = ['/login'] // no redirect whitelist
 
// 导航守卫
router.beforeEach((to, from, next) => {
  NProgress.start()
  try {
    // 判断是否已经获取过动态菜单,未获取,则需要获取一次
    if (store.getters.dynamicRoutes.length === 0) {
      if (whiteList.indexOf(to.path) !== -1) {
        next()
      } else {
        getRouter().then(res => {
          if (res.code === 0) {
            let menuRouter = fnAddDynamicMenuRoutes(res.data[0].children)
            store.dispatch('app/dynamicRoutes', menuRouter).then(() => {
              router.addRoutes(store.getters.dynamicRoutes)
              next({...to, replace: true})
            })
          } else {
            console.log('获取动态路由失败!')
            next({path: '/login'})
          }
        })
      }
    } else {
      // 路由已存在或已缓存路由
      if (to.meta.requireAuth) {
        if (sessionStorage.getItem('loginName') !== null) {
          // 判断本地是否存在token
          next()
        } else {
          // 未登录,跳转到登陆页面
          next({path: '/login'})
        }
      } else {
        if (whiteList.indexOf(to.path) !== -1) {
          next()
        } else {
          if (sessionStorage.getItem('loginName') !== null) {
            // 判断本地是否存在token
            next(`/?redirect=${to.path}`)
          } else {
            next(`/login?redirect=${to.path}`)
          }
        }
      }
    }
  } catch (error) {
    console.log('出错了')
    next(`/login?redirect=${to.path}`)
  }
})
 
router.afterEach(() => {
  // 在即将进入新的页面组件前,关闭掉进度条
  NProgress.done()
})
 

注释写的比较详细了,主要说下思路:

首先确定获取动态菜单数据的时机。一般在登录成功跳转到主页面时,获取动态菜单数据。
   由于涉及到路由的跳转(登录页面 -> 主页面),所以可以使用 beforeEach 进行路由导航守卫操作。
   但由于每次路由跳转均会触发 beforeEach ,所以为了防止频繁获取动态路由值,这里采用vuex方式存储了获取的路由信息,如果已获取路由,就直接跳转,否则就获取一次动态菜单数据并处理。

如果不采用vuex方式也可以存到sessionStorage里面,总之就是保存一下获取的路由信息,以免重复获取。
4接下来看一看,store的写法

 
const state = {
  dynamicRoutes: []
}
 
const mutations = {
  DYNAMIC_ROUTES (state, routes) {
    state.dynamicRoutes = routes
  }
}
 
const actions = {
  dynamicRoutes ({commit}, routes) {
    commit('DYNAMIC_ROUTES', routes)
  }
}

注意:vue是单页面应用程序,所以页面一刷新数据部分数据也会跟着丢失,所以我们需要将store中的数据存储到本地,才能保证路由不丢失。

到这里,动态路由就已经配置好了,总体来说不是很难,主要是有坑!但只要理清了思路,写起代码就会很清晰。

说一些笔者遇到的问题,

1.首先是component动态导入的问题,由于webpack的版本不同,需要根据情况来采用import和require方式来导入,如果导入不正确多半会报错,找不到module等等。或者不报错,但路由跳转是空白页。如果导入正确则一定可以跳转正常,否则,请查找正确的导入方法!路由跳转正确,能显示跳转的组件,就完成了一大半!

2.路由的跳转的地方,由于我们项目采用的是左侧菜单栏,有二级菜单,所以当路由跳转正常时,还需确定路由跳转所渲染的位置是否正确!

后记:

在刷新页面时遇到一个问题,动态路由表会随着vuex的刷新而消失。

处理:这里在app.vue页面刷新时利用sessionStorage存储一下store,防止刷新丢失vuex。

如下:

export default {
  name: 'App',
  created () {
    // 在页面加载时读取sessionStorage里的状态信息
    if (sessionStorage.getItem('storeData')) {
      this.$store.replaceState(Object.assign({}, this.$store.state, JSON.parse(sessionStorage.getItem('storeData'))))
    }
    // 在页面刷新时将vuex里的信息保存到sessionStorage里
    window.addEventListener('beforeunload', () => {
      sessionStorage.setItem('storeData', JSON.stringify(this.$store.state))
    })
    // 兼容iphone手机
    window.addEventListener('pagehide', () => {
      sessionStorage.setItem('storeData', JSON.stringify(this.$store.state))
    })
  }
}

另外,在登录成功后也获取了一下动态路由。这样处理下来,刷新时也不会丢失路由了!

// 获取动态路由
getRouter().then(res => {
  if (res.code === 0) {
    let menuRouter = fnAddDynamicMenuRoutes(res.data[0].children)
    store.dispatch('app/dynamicRoutes', menuRouter).then(() => {
      router.addRoutes(store.getters.dynamicRoutes)
    })
    console.log(store.getters.dynamicRoutes)
  } else {
    console.log('获取动态路由失败!')
    router.push('/login')
  }
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/408330.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

css清除浮动的四种方法(详细)

浮动带来的影响 清除浮动主要是为了解决&#xff0c;父元素因为子级元素浮动引起的内部高度为0的问题 看下面一段代码 <div class"fater"><div class"box1">one</div><div class"box2">two</div></div> …

VUE中调用高德地图获取当前位置(VUE2.0和3.0通用)

标签&#xff1a; Vue vue 定位 js javascript1、去高德开放平台获取高德地图KEY地址&#xff1a;https://lbs.amap.com/注意&#xff1a;这里一定要选择WEB端的KEY&#xff0c;不要选择WEB服务的KEY&#xff0c;否则拿不到数据2、去项目中引入KEY&#xff0c;也就是CDN&#x…

基于RuoYi框架自动生成后端代码及前端界面

&#x1f3c0;&#xff08;1&#xff09;序言 &#x1f438;近来工作临近项目周期尾声&#xff0c;基本都是每天加班到晚上8到9点的节奏&#xff0c;似乎每年到10月份之际都是一个忙碌月&#xff0c;不知道这是一个&#x1f436;行业规律&#x1f436;还是仅仅对我而言的一个&a…

在vue中使用FullCanlendar实现日历预约会议室功能

最近接到任务,让实现一个预约功能,让我找找插件,需求是这个样子滴 明白任务以后,那咱就开抄呗~(bushi 开找 经过一番寻找,最后我决定使用FullCalendar,为啥用这个呢,你看它样子长的像不像我的需求,虽然说不上是有一些像吧,但简直就是一模一样. 更关键的是这玩意有很全的文档(但…

H5移动端适配方案rem/vw

前言 在讲解适配方案之前&#xff0c;我们聊聊为什么要做适配&#xff1f; 因为视口、逻辑像素、分辨率这些变量的不同&#xff0c;在每个设备展示都不一样&#xff0c;需要一种方案来统一。 物理像素&#xff1a;也就是分辨率&#xff0c;一个物理像素是显示器上的最小的物…

项目无法识别 ?. 语法,导致报错Module parse failed: Unexpected token

一、第一种情况是如果你需要引入的组件库源码的过程中&#xff0c;比如你要import一个封装好的组件这种场景&#xff1a; 首先找到报这个问题的地方 我这里是因为es语法问题 如果你也是npm安装了一个包&#xff0c;然后在导入的时候报这个语法错&#xff0c;那你可以接着往下…

【前端趋势】Vue、Vite作者尤雨溪前端趋势2022主题演讲

欢迎来到我的博客 &#x1f4d4;博主是一名大学在读本科生&#xff0c;主要学习方向是前端。 &#x1f36d;目前已经更新了【Vue】、【React–从基础到实战】、【TypeScript】等等系列专栏 &#x1f308;博客主页&#x1f449;codeMak1r.的博客 最新专栏【React–从基础到实战】…

Vant UI 中 van-collapse 下拉折叠面板如何默认展开第一项

问题重现 最近在做项目时&#xff0c;有一个需求是让 van-collapse 下拉折叠面板的第一项默认是展开状态&#xff1b;我使用到了 Vant UI 组件&#xff0c;首先按照官网文档的写法直接引入&#xff1a; <!--下拉折叠面板--><van-collapse class"collapse" …

vue路由的安装和使用

TOCVue 路由 vue-router 1 安装vue-router npm i vue-router -s 2 创建路由模块 // src/router/index.js就是当前项目的路由模块 // 1 导入Vue 和VueRouter的包 import Vue from vue import VueRouter from vue-router // 导入路由要用到的组件 import Home from ../component…

【TypeScript介绍】一文带你初步了解TypeScript

前言 博主主页&#x1f449;&#x1f3fb;蜡笔雏田学代码 专栏链接&#x1f449;&#x1f3fb;【TypeScript专栏】 今天开始学习学习TypeScript这门语言&#xff01; 感兴趣的小伙伴一起来看看吧~&#x1f91e; 文章目录TypeScript介绍1. TypeScript是什么2. TypeScript为什么要…

大文件上传

大文件上传原理 当我们在做文件上传的功能时&#xff0c;如果上传的文件过大&#xff0c;可能会导致长传时间特别长&#xff0c;且上传失败后需要整个文件全部重新上传。因此&#xff0c;我们需要前后端配合来解决这个问题。 最常用的解决方案就是 —— 切片上传。 这次我们…

图文详解uni-app PC端宽屏适配方案

图文详解uni-app PC端宽屏适配方案 随着互联网的发展&#xff0c;iOS、Android、H5以及各种小程序快应用层出不穷&#xff0c;随之而来的问题就是如何用一套代码&#xff0c;适配多个平台&#xff0c;其中uni-app表现优异&#xff0c;已经实现了手机端全覆盖&#xff0c;支持i…

【JavaScript速成之路】JavaScript对象

&#x1f4c3;个人主页&#xff1a;「小杨」的csdn博客 &#x1f525;系列专栏&#xff1a;【JavaScript速成之路】 &#x1f433;希望大家多多支持&#x1f970;一起进步呀&#xff01; 文章目录前言1&#xff0c;初识对象1.1&#xff0c;对象概念1.2&#xff0c;对象创建1.2.…

手撕前端面试题【JavaScript】

前端的那些基本标签&#x1f353;&#x1f353; 浅拷贝&#x1f353;&#x1f353;简易深拷贝&#x1f353;&#x1f353;深拷贝&#x1f353;&#x1f353;什么是深拷贝&#xff0c;什么是浅拷贝&#xff0c;二者有什么区别&#xff0c;平时改怎么区分呢&#xff1f;&#x1f…

vue3.0本地引入vue.js

第一步获取vue版本 Vue的各种版本介绍&#xff1a; cjs&#xff08;两个版本都是完整版&#xff0c;包含编译器&#xff09; vue.cjs.js vue.cjs.prod.js&#xff08;开发版&#xff0c;代码进行了压缩&#xff09; global&#xff08;这四个版本都可以在浏览器中直接通过…

Vue中 provide、inject 详解及使用

传送门&#xff1a;Vue中 子组件向父组件传值 及 .sync 修饰符 详解 传送门&#xff1a;Vue中 状态管理器&#xff08;vuex&#xff09;详解及应用场景 传送门&#xff1a;Vue中 $ attrs、$ listeners 详解及使用 传送门&#xff1a;Vue中 事件总线&#xff08;eventBus&#x…

New Bing申请与使用教程

&#xff08;1&#xff09;安装 Edge 浏览器插件&#xff1a; 由于在 CN 访问 Bing 国际版会自动跳转到 CN 版&#xff0c;因此需要先重定向浏览器的 Header&#xff0c;先在 Edge 浏览器安装插件&#xff1a;Header Editor&#xff1a; 添加如下配置&#xff08;其中&#xf…

① 尚品汇的后台管理系统【尚硅谷】【Vue】

后台管理系统项目简介 什么是后台管理系统项目&#xff1f; 在前端领域当中&#xff0c;开发后台管理系统项目&#xff0c;并非是Java&#xff0c;PHP等后台语言项目 在前面课程当中&#xff0c;我们已经开发了一个项目【尚品汇电商平台项目】&#xff0c;这个项目主要针对的是…

HTML5+CSS3模拟实现《亮剑》平安县城一役精彩微信群聊-谁开的炮?

转眼从2005年到现在&#xff0c;《亮剑》已经播出多年&#xff0c;但热度依然不减&#xff0c;而且每次重温我都会看出不一样的意蕴&#xff0c;今天&#xff0c;我就用HTML5CSS3模拟实现《亮剑》平安县城一役精彩微信群聊-谁开的炮&#xff1f; 目录 1. 实现思路 2. 素材介绍…

零基础JavaScript学习【第四期】

博主有话说:不知不觉这一已经第四期了,感谢大家的支持。 个人空间:GUIDM的个人空间 专栏内容:零基础JavaScript学习 基础还是关键。 欢迎大家的一键三连。 往期回顾: 前情回顾:第一期https://blog.csdn.net/m0_61901625/article/details/124772807?spm=1001.2014.3001.…