vue-element-admin解决三级目录的KeepAlive缓存问题(详情版)

vue-element-admin解决三级目录的KeepAlive缓存问题(详情版)

本文章将从问题出现的角度看看KeepAlive的缓存问题,然后提出两种解决方法。本文章比较详细,如果只是看怎么解决,代码怎么改,请前往配置版。

一、解决问题之间,先理清问题出现的原因

①首先,观察一下“一级目录”和“二级目录”

通过vue devtools工具,截图如下。
可以看到,“一级目录”——Tab,可以缓存:
在这里插入图片描述

再看看,“二级目录”——DirectivePermission,也可以缓存:
在这里插入图片描述

可以发现,他们都在<App>——<Layout>——<AppMain>下,同时<KeepAlive>的include属性包含组件配置的“name”(如上面两图所示)。

②再看看,“三级目录”的情况

通过vue devtools工具,截图如下。
可以看到,“三级目录”——Menu1-1,不可以缓存:
在这里插入图片描述

看发现,其明细的不同,他在<App>——<Layout>——<AppMain>——<Menu1>下,比“一级目录”和“二级目录”多了<Menu1>。由于<KeepAlive>的include属性并不包含<Menu1>组件配置的name——“Menu1”,而是组件配置的name——“Menu1-1”(如下图),所有不缓存。更多<keep-alive>不缓存的原因,可以看个人的另一篇文章。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、解决问题

①添加<RouterViewKeepAlive>解决

这里,你可能想到。既然,“三级目录”不缓存的原因是“由于<KeepAlive>的include属性并不包含<Menu1>组件配置的name——‘Menu1’”。那我在的include属性上,始终包含“Menu1”就行了(网上已经早有人写过类似解决方法,本文章的该解决方法也是参考该文章——见该文章)。

  • 首先,添加<RouterViewKeepAlive>组件
    新目录:src\layout\components\RouterViewKeepAlive\RouterViewKeepAlive.vue

    <!-- 父级路由组件,用于二级路由上, 该二级可以被keep-alive缓存 -->
    <!-- 由于该二级可以被keep-alive缓存,所以其三级的内容将保存 -->
    <!-- 注意:面包屑关闭后,不会从KeepAlive的include属性清除 -->
    <template>
      <div class="app-main">
        <router-view />
      </div>
    </template>
    <script>
    export default {
      name: 'RouterViewKeepAlive'
    }
    </script>
    <style lang="scss" scoped>
      .app-main {
        
      }
    </style>
    
  • 然后,在<AppMain>添加“cachedViews”计算属性上添加“RouterViewKeepAlive”
    目录:src\layout\components\AppMain.vue

    <script>
    export default {
      name: 'AppMain',
      computed: {
        cachedViews() {
          // return this.$store.state.tagsView.cachedViews
          // 加入RouterViewKeepAlive组件,总是缓存二级目录路由配置为“RouterViewKeepAlive”的
          return ['RouterViewKeepAlive', ...this.$store.state.tagsView.cachedViews]
        },
        key() {
          return this.$route.path
        }
      }
    }
    </script>
    
  • 最后,修改路由配置(以原项目Nested Routes路由配置nested.js为例)
    目录:src\router\modules\nested.js

    /** When your routing table is too long, you can split it into small modules **/
    
    import Layout from '@/layout'
    // 导入RouterViewKeepAlive
    import RouterViewKeepAlive from '@/layout/components/RouterViewKeepAlive/RouterViewKeepAlive.vue'
    
    const nestedRouter = {
      path: '/nested',
      component: Layout,
      redirect: '/nested/menu1/menu1-1',
      name: 'Nested',
      meta: {
        title: 'Nested Routes',
        icon: 'nested'
      },
      children: [
        {
          path: 'menu1',
          // component: () => import('@/views/nested/menu1/index'), // Parent router-view
          component: RouterViewKeepAlive, // 使用RouterViewKeepAlive作为二级组件
          // name: 'Menu1',
          name: 'RouterViewKeepAlive', // 名字改为“RouterViewKeepAlive”,虽然没必要,但为了维护性
          meta: { title: 'Menu 1' },
          redirect: '/nested/menu1/menu1-1',
          children: [
            {
              path: 'menu1-1',
              component: () => import('@/views/nested/menu1/menu1-1'),
              name: 'Menu1-1',
              meta: { title: 'Menu 1-1' }
            },
            {
              path: 'menu1-2',
              component: () => import('@/views/nested/menu1/menu1-2'),
              name: 'Menu1-2',
              redirect: '/nested/menu1/menu1-2/menu1-2-1',
              meta: { title: 'Menu 1-2' },
              children: [
                {
                  path: 'menu1-2-1',
                  component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'),
                  name: 'Menu1-2-1',
                  meta: { title: 'Menu 1-2-1' }
                },
                {
                  path: 'menu1-2-2',
                  component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'),
                  name: 'Menu1-2-2',
                  meta: { title: 'Menu 1-2-2' }
                }
              ]
            },
            {
              path: 'menu1-3',
              component: () => import('@/views/nested/menu1/menu1-3'),
              name: 'Menu1-3',
              meta: { title: 'Menu 1-3' }
            }
          ]
        },
        {
          path: 'menu2',
          name: 'Menu2',
          component: () => import('@/views/nested/menu2/index'),
          meta: { title: 'Menu 2' }
        }
      ]
    }
    
    export default nestedRouter
    
    

    注意:由于配置了“component: RouterViewKeepAlive”,使用了<RouterViewKeepAlive>作为二级组件,替换了’@/views/nested/menu1/index’的<Menu1>组件。

  • 结果
    可以看到“三级或以上的目录”被成功缓存了
    在这里插入图片描述

注意:这种实现方式存在弊端,就是永远关不掉(TagsView上的关闭),会一直占用内存
在这里插入图片描述

②转变Router配置解决

现在方法一,存在“关闭面包屑却不会关闭该缓存,会一直占用内存”的弊端,那怎么解决呢?
那找一下关闭<keep-alive>缓存的方法,不就解决了吗?
由于vue-element-admin项目是通过<keep-alive>的include来完成的,include如果没有加上“RouterViewKeepAlive”,就会将所有的<RouterViewKeepAlive>没缓存,这不是我们想要的。我们想要的是“缓存对应key的<RouterViewKeepAlive>,然后移除对应key的<RouterViewKeepAlive>”。
但是,个人看了官网并未提供或暴露这种特殊的方法接口。

那现在我们换一种思路——“注册路由时,将三级或以上的路由配置转换为一级和二级的那样”,如下图:
在这里插入图片描述
由于vue-element-admin项目在左侧菜单栏等地方用到了@/store的permission.js的“routes”。所以,现在的思路是“只改变Router的挂载,其他保持不改”,步骤如下。

  • 首先,对permission.js,添加flattenRoutes方法和修改generateRoutes
    目录:src\store\modules\permission.js

    // ...
    /**
     * 将单个路由,假如有三级或三级目录,则转为二级目录格式
     * @param {Object} router 要处理的路由
     * @returns {Object} 处理后的路由
     */
    function flattenRouter(router) {
      // 创建一个新的对象来存储转换后的路由
      const newRouter = {
        ...router,
        children: []
      }
      const routerChildren = router.children
      // 从根路由开始扁平化
      if (routerChildren && routerChildren.length > 0) {
        flatten('', routerChildren)
      }
      /**
       * 递归函数来遍历和扁平化路由
       * @param {String} parentPath 父路由路径
       * @param {Array} routes 路由
       */
      function flatten(parentPath, routes) {
        routes.forEach(route => {
          const { path, children } = route
          // 构建完整的路径
          const fullPath = `${parentPath}${path.startsWith('/') ? path.slice(1) : path}`
          // 如果当前路由有子路由,则递归处理
          if (children && children.length > 0) {
            flatten(`${fullPath}/`, children)
          } else {
            // 否则,将当前路由添加到新的children数组中
            newRouter.children.push({
              ...route,
              path: fullPath
            })
          }
        })
      }
      return newRouter
    }
    
    /**
     * 处理路由,将三级或三级以上目录的转为二级目录格式
     * @param {Array} routes routes
     * @param {Array} 处理后的路由
     */
    export function flattenRoutes(routes) {
      const res = []
      routes.forEach(route => {
        const newRouter = flattenRouter(route)
        res.push(newRouter)
      })
      return res
    }
    
    // ...
    const actions = {
      generateRoutes({ commit }, roles) {
        return new Promise(resolve => {
          let accessedRoutes
          if (roles.includes('admin')) {
            accessedRoutes = asyncRoutes || []
          } else {
            accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
          }
          // 处理路由,将三级或三级以上目录的转为二级目录格式
          const flattenAccessedRoutes = flattenRoutes(accessedRoutes)
          // store存的是accessedRoutes,用于左侧边导航栏,多级目录(包含三级或以上)
          commit('SET_ROUTES', accessedRoutes)
          // resolve(accessedRoutes)
          // Promise的resolve出去的是flattenAccessedRoutes,用于路由,多级目录(已转换为二级目录格式,不包含三级或以上)
          resolve(flattenAccessedRoutes)
        })
      }
    }
    // ...
    

    完整代码如下:

    import { asyncRoutes, constantRoutes } from '@/router'
    
    /**
     * Use meta.role to determine if the current user has permission
     * @param roles
     * @param route
     */
    function hasPermission(roles, route) {
      if (route.meta && route.meta.roles) {
        return roles.some(role => route.meta.roles.includes(role))
      } else {
        return true
      }
    }
    
    /**
     * Filter asynchronous routing tables by recursion
     * @param routes asyncRoutes
     * @param roles
     */
    export function filterAsyncRoutes(routes, roles) {
      const res = []
    
      routes.forEach(route => {
        const tmp = { ...route }
        if (hasPermission(roles, tmp)) {
          if (tmp.children) {
            tmp.children = filterAsyncRoutes(tmp.children, roles)
          }
          res.push(tmp)
        }
      })
    
      return res
    }
    
    /**
     * 将单个路由,假如有三级或三级目录,则转为二级目录格式
     * @param {Object} router 要处理的路由
     * @returns {Object} 处理后的路由
     */
    function flattenRouter(router) {
      // 创建一个新的对象来存储转换后的路由
      const newRouter = {
        ...router,
        children: []
      }
    
      const routerChildren = router.children
      // 从根路由开始扁平化
      if (routerChildren && routerChildren.length > 0) {
        flatten('', routerChildren)
      }
    
      /**
       * 递归函数来遍历和扁平化路由
       * @param {String} parentPath 父路由路径
       * @param {Array} routes 路由
       */
      function flatten(parentPath, routes) {
        routes.forEach(route => {
          const { path, children } = route
          // 构建完整的路径
          const fullPath = `${parentPath}${path.startsWith('/') ? path.slice(1) : path}`
          // 如果当前路由有子路由,则递归处理
          if (children && children.length > 0) {
            flatten(`${fullPath}/`, children)
          } else {
            // 否则,将当前路由添加到新的children数组中
            newRouter.children.push({
              ...route,
              path: fullPath
            })
          }
        })
      }
    
      return newRouter
    }
    
    /**
     * 处理路由,将三级或三级以上目录的转为二级目录格式
     * @param {Array} routes routes
     * @param {Array} 处理后的路由
     */
    export function flattenRoutes(routes) {
      const res = []
      routes.forEach(route => {
        const newRouter = flattenRouter(route)
        res.push(newRouter)
      })
      return res
    }
    
    const state = {
      routes: [],
      addRoutes: []
    }
    
    const mutations = {
      SET_ROUTES: (state, routes) => {
        state.addRoutes = routes
        state.routes = constantRoutes.concat(routes)
      }
    }
    
    const actions = {
      generateRoutes({ commit }, roles) {
        return new Promise(resolve => {
          let accessedRoutes
          if (roles.includes('admin')) {
            accessedRoutes = asyncRoutes || []
          } else {
            accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
          }
          // 处理路由,将三级或三级以上目录的转为二级目录格式
          const flattenAccessedRoutes = flattenRoutes(accessedRoutes)
          // store存的是accessedRoutes,用于左侧边导航栏,多级目录(包含三级或以上)
          commit('SET_ROUTES', accessedRoutes)
          // resolve(accessedRoutes)
          // Promise的resolve出去的是flattenAccessedRoutes,用于路由,多级目录(已转换为二级目录,不包含三级或以上)
          resolve(flattenAccessedRoutes)
        })
      }
    }
    
    export default {
      namespaced: true,
      state,
      mutations,
      actions
    }
    
  • 然后,进行测试
    更改文件如下:
    修改nested.js的name:‘Menu1-1’→’Menu11’。同理,‘Menu12’、‘Menu121’、‘Menu122’、‘Menu13’。
    目录:src\router\modules\nested.js

    /** When your routing table is too long, you can split it into small modules **/
    
    import Layout from '@/layout'
    
    const nestedRouter = {
      path: '/nested',
      component: Layout,
      redirect: '/nested/menu1/menu1-1',
      name: 'Nested',
      meta: {
        title: 'Nested Routes',
        icon: 'nested'
      },
      children: [
        {
          path: 'menu1',
          // component: () => import('@/views/nested/menu1/index'), // Parent router-view
          name: 'Menu1',
          meta: { title: 'Menu 1' },
          redirect: '/nested/menu1/menu1-1',
          children: [
            {
              path: 'menu1-1',
              component: () => import('@/views/nested/menu1/menu1-1'),
              name: 'Menu11', // 已更改,便于测试
              meta: { title: 'Menu 1-1' }
            },
            {
              path: 'menu1-2',
              // component: () => import('@/views/nested/menu1/menu1-2'),
              name: 'Menu12', // 已更改,便于测试
              redirect: '/nested/menu1/menu1-2/menu1-2-1',
              meta: { title: 'Menu 1-2' },
              children: [
                {
                  path: 'menu1-2-1',
                  component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'),
                  name: 'Menu121', // 已更改,便于测试
                  meta: { title: 'Menu 1-2-1' }
                },
                {
                  path: 'menu1-2-2',
                  component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'),
                  name: 'Menu122', // 已更改,便于测试
                  meta: { title: 'Menu 1-2-2' }
                }
              ]
            },
            {
              path: 'menu1-3',
              component: () => import('@/views/nested/menu1/menu1-3'),
              name: 'Menu13', // 已更改,便于测试
              meta: { title: 'Menu 1-3' }
            }
          ]
        },
        {
          path: 'menu2',
          name: 'Menu2',
          component: () => import('@/views/nested/menu2/index'),
          meta: { title: 'Menu 2' }
        }
      ]
    }
    
    export default nestedRouter
    

    修改‘menu1-1\index.vue’,添加和nested.js配置一样的name属性。同理,‘menu1\menu1-2\menu1-2-1\index.vue’、‘menu1\menu1-2\menu1-2-2\index.vue’、‘menu1\menu1-3\index.vue’(注意:同时,将开头的“<template functional>”改为“<template>”)。
    以menu1-1为例,代码如下,其他的同理。
    目录:src\views\nested\menu1\menu1-1\index.vue

    <template>
      <div style="padding: 30px">
        <el-alert :closable="false" title="menu 1-1" type="success">
          <router-view />
        </el-alert>
      </div>
    </template>
    <!-- 修改后 -->
    <script>
    export default {
      // 添加name属性,让keep-alive进行缓存
      name: 'Menu11'
    }
    </script>
    
  • 结果
    可以看到“三级或以上的目录”被成功缓存了
    在这里插入图片描述

注意事项:
①与方法一“添加<RouterViewKeepAlive>解决”的区别:
方法一是“使用了<RouterViewKeepAlive>作为二级组件,替换了’@/views/nested/menu1/index’的<Menu1>组件。”;
而方法二是“扁平化路由”,就如上方测试改nested.js那样,一些“component”的配置是没意义的,所以注释掉了
这种实现方式同样存在弊端,就是Breadcrumb 面包屑多级关系不见了。因为,由于vue-element-admin项目Breadcrumb 面包屑是通过$route来实现的,而我们恰好改的就是路由配置。区别如下:
在这里插入图片描述
在这里插入图片描述
③上面,添加flattenRoutes方法只是对“accessedRoutes”做了处理,还未对“constantRoutes”处理,比如同时对“constantRoutes”处理。处理代码如下:
目录:src\router\index.js

// ...
/* 处理路由 */
import { flattenRoutes } from '@/store/modules/permission'

// ...
const createRouter = () => new Router({
  // mode: 'history', // require service support
  scrollBehavior: () => ({ y: 0 }),
  // routes: constantRoutes
  // 处理路由,将三级或三级以上目录的转为二级目录格式
  routes: flattenRoutes(constantRoutes)
})
// ...

③直接移除include解决

此方法官方文档此次提到“前往@/layout/components/AppMain.vue文件下,移除include相关代码即可。当然直接使用 keep-alive 也是有弊端的,他并不能动态的删除缓存,你最多只能帮它设置一个最大缓存实例的个数 limit。

更改如下:
目录:src\layout\components\AppMain.vue

<template>
  <section class="app-main">
    <transition name="fade-transform" mode="out-in">
      <!-- 移除include -->
      <!-- <keep-alive :include="cachedViews"> -->
      <keep-alive>
        <router-view :key="key" />
      </keep-alive>
    </transition>
  </section>
</template>
// ...

如果,想要设置最大缓存个数,比如设置最大10个。只需将“<keep-alive>”改为“<keep-alive :max=“10”>”

注意事项:
①该方法的弊端:官方文档说的也很清楚了——“他并不能动态的删除缓存,只能帮它设置一个最大缓存实例的个数”。
②与方法一的对比:没使用了<RouterViewKeepAlive>作为二级组件,替换了’@/views/nested/menu1/index’的<Menu1>组件;该方法的“他并不能动态的删除缓存”的范围比方法一的范围大,该方法所有的目录都不能动态删除缓存,而方法一是三级或以上的目录不能移除。
③与方法二的对比:没“扁平化路由”无方法二的弊端——Breadcrumb 面包屑多级关系不见了

三、总结

vue-element-admin解决三级目录的KeepAlive缓存问题:
①添加<RouterViewKeepAlive>解决
弊端:永远关不掉(TagsView上的关闭),会一直占用内存
(可以给keep-alive设置一个最大缓存实例的个数,但不一定满足项目需求;如果该项目三级或以上的目录不多,就几个,那还能接受内存的占用)

②转变Router配置解决
弊端:Breadcrumb 面包屑多级关系不见了
(如果真实项目,无需“Breadcrumb 面包屑”同时最多三级(见方法二的“注意事项”),还可以接受。)

③直接移除include解决
弊端:他并不能动态的删除缓存,只能帮它设置一个最大缓存实例的个数
(如果真实项目,可以接受“不能动态的删除缓存”和“设置最大缓存实例的个数”的弊端,那该方法是最简单的解决方法。)

这里强调一下:由于上述方法是对原本vue-element-admin项目构建上的修复,一旦按照文章修复了,一定要记得项目的可维护性,不然,下一个接手该项目的码农将会很疑惑。比如,在真实项目的“README.md”上添加修改的文字描述和路由配置注意事项,同时在src\router\index.js的路由配置上注释好。

最终,似乎都没有十全十美的解决方案,每一种方案总是存在一些“舍去”。就vue-element-admin的作者在文档提过“如果没有标签导航栏需求的用户,建议移除此功能”。

网上也有更多的解决方法,比如:

  • 使用created解决
  • 设置hidden:true隐藏

如果想了解更多关于vue-element-admin项目<keep-alive>不缓存的原因,也欢迎看看个人的另一篇文章。
如果大家有其他更完美的解决方案或者本文章方法的不足之处,欢迎在评论区讨论!

四、参考文献

  • sweet202005——解决vue项目三级菜单路由无法缓存问题
  • Vue2——keep-alive

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【原创教程】电气电工07:网线的制作方法

电气电工经常会遇到做网线,我们做网线需要网线钳与测试仪。需要了解网线的两种接线标准。 我们来看一下网线钳的操作步骤: 这种压线钳也同时具有剥线、剪线功能。 用这种网线钳能制作RJ45网络线接头。RJ11电话线接头、4P电话线接头。适用于RJ45,RJ11型网线 做网线的时候我…

Temu全托管和半托管的区别:一文说清temu全托和半托的差异

TEMU在今年3月再出王炸&#xff0c;上线半托管模式。这是TEMU继全托管模式爆火跨境圈之后的又一个大动作。那么&#xff0c;TEMU全托管和TEMU半托管有哪些不同&#xff1f;卖家朋友应该如何选择呢&#xff1f;今天给大家详细拆解一下。 TEMU全托管和半托管有什么区别 首先是定…

汇编语言lea指令取数组偏移地址

最近看到一条指令&#xff0c;x86汇编&#xff0c; LEA BX, 6[DI] 根据资料&#xff0c;它的含义是&#xff0c;某数组含20个元素&#xff0c;每个元素占一个字节&#xff0c;序号为0~19。设DI指向数组开头处&#xff0c;把序号为6的元素的偏移地址送到BX中&#xff1b; lea指令…

如何进行长截图的两种方法

前言 本文主要讲2种截图方式&#xff0c;分别是谷歌和QQ。 谷歌分为Web端 和 移动端&#xff0c;选一种即可。 第一种&#xff1a;谷歌浏览器控制台自带的 1.先把控制台语言更改为中文&#xff0c;方便查看 ①.按F12&#xff0c;点击设置面板 ②.修改语言为中文并关闭 ③.点击…

BFS解决单源最短路问题

目录 迷宫中离入口最近的出口 最小基因变化 单词接龙 为高尔夫比赛砍树 迷宫中离入口最近的出口 题目 思路 使用宽度优先遍历解决这道题&#xff0c;需要一个二维数组标记是否被遍历过&#xff0c;也需要一个队列辅助完成宽度优先遍历&#xff0c;类似于水波纹一样&#x…

java接口 controller层接收list集合传参,postman 调用接口时required parameter XXX is not present

开发过程中开发一个java接口 controller层接收list集合传参&#xff0c;然后postman调用一直不成功&#xff0c;报错 使用RequestParam方式&#xff0c;如果postman 调用接口时报错required parameter XXX is not present 可能是&#xff08;value“items”&#xff09;跟你输…

线索获取:多渠道获客策略解析

在当今商业环境中&#xff0c;企业面临着激烈的市场竞争和不断变化的客户需求。在此背景下&#xff0c;销售线索作为销售活动的基础和起点&#xff0c;重要性更加凸显&#xff0c;尤其是在营销精耕的当下&#xff0c;做好线索的精细化管理成为企业获取竞争优势的关键环节之一。…

数据结构----队列

1 什么是队列&#xff1f; 只允许在两端进行插入和删除操作的线性表&#xff0c;在队尾插入&#xff0c;在队头删除 插入的一端&#xff0c;被称为"队尾"&#xff0c;删除的一端被称为"队头" 在队列操作过程中&#xff0c;为了提高效率&#xff0…

《重生到现代之从零开始的C语言生活》—— 指针3

数组名的理解 在我们使用&arr[0]的方式拿到了数组第一个元素的地址&#xff0c;但是其实&#xff0c;数组名本来就地址&#xff0c;而且是数组首元素的地址 所以数组名就是数组首元素的地址 但是会有两个例外 sizeof(数组名)&#xff0c;sizeof中单独放数组名&#xff0c…

[Linux] 查看系统资源 (持续更新中)

概述 在Linux中&#xff0c;有许多命令和工具可用于查看系统的资源使用情况。以下是一些常用的方式&#xff1a; top&#xff1a;top命令是最常见的实时系统监视工具之一。它显示了当前运行的进程列表&#xff0c;以及每个进程的CPU、内存使用情况、nice值等信息。top命令还会…

帆软报表,达梦数据库驱动上传失败

1、按照正常操作新建数据库连接&#xff0c;上传准备好的达梦驱动时&#xff0c;提示如图一需要修改SystemConfig.driverUpload为true才可以。 2、FineDB存储了数据决策系统中除平台属性配置以外的所有信息。详情请参见&#xff1a; FineDB 数据库简介。 3、因此管理员可通过…

Kubectl基础命令使用

一.Kubectl 基础命令 格式&#xff1a; kubectl [command] [TYPE] [NAME] [FLAGS] kubectl 是 Kubernetes 的命令行工具&#xff0c;用于管理 Kubernetes 集群。以下是一些常用的 kubectl 命令及其选项&#xff1a; 常用命令 获取资源 列出所有资源类型&#xff08;Pods、De…

机器学习|什么是梯度下降(小白向)|探寻最优解之路

文章目录 前言一、什么是梯度下降&#xff1f;二、梯度下降法一般步骤1.确定一个小目标——预测函数2.找到差距——代价函数3.明确搜索方向——梯度计算4.一步要走多远&#xff1f;——学习率 三、梯度下降的分类批量梯度下降&#xff08;Batch Gradient Descent&#xff09;随…

2007-2022年上市公司资源节约数据

2007-2022年上市公司资源节约数据 1、时间&#xff1a;2007-2022年 2、来源&#xff1a;上市公司年报、社会责任报告、上市公司网站信息 3、指标&#xff1a;水资源节约、电力节约、原煤节约、天然气节约、汽油节约、柴油节约、集中供热节约、折算成统一标准煤共计节约 4、…

flume--数据从kafka到hdfs发生错误

解决&#xff1a; #1.将flume自带的依赖删除 mv /opt/installs/flume1.9/lib/guava-11.0.2.jar /opt/installs/flume1.9/lib/guava-11.0.2.jar.bak #2.将hadoop的依赖发送到flume下 cp /opt/installs/hadoop3.1.4/share/hadoop/common/lib/guava-27.0-jre.jar /opt/installs/f…

有哪些同声传译软件?精选5款实用工具

在浪漫之都巴黎&#xff0c;每一步都踏着历史与艺术的韵律。从埃菲尔铁塔下仰望的震撼&#xff0c;到塞纳河畔悠闲的咖啡时光&#xff0c;打卡巴黎地标已不再满足于传统方式。 如今&#xff0c;#打卡巴黎地标的方式nextlevel了#&#xff0c;科技与文化的碰撞开启了全新的体验篇…

『基础』线性代数-1行列式

行列式是什么-运算规则 排列&#xff1a;不同的 n 元排列共有 n! 个 逆序&#xff1a;小数排在大数后面&#xff0c;叫逆序&#xff1b;一个排列中逆序的总和叫做这个排列的逆序数&#xff0c;记为 τ ( j 1 , . . . , j n ) \tau(j_1,...,j_n) τ(j1​,...,jn​) 逆序数的计…

IP SSL证书的未来趋势:适应不断变化的安全挑战

随着网络攻击手段的不断进化和用户对隐私保护意识的增强&#xff0c;IP SSL证书作为保障网络安全的关键组件之一&#xff0c;也在不断地发展和完善。本文将探讨IP SSL证书的未来趋势&#xff0c;以及如何适应这些不断变化的安全挑战。 当前状况与挑战 网络安全意识提升&#…

LORA通信详解

LORA&#xff08;Long Range Radio&#xff09;是一种低功耗广域网&#xff08;LPWAN&#xff09;技术&#xff0c;专门设计用于物联网&#xff08;IoT&#xff09;设备的远距离通信。其长距离传输和低功耗特性使其在智能城市、环境监测、农业等领域中得到了广泛应用。 一、LOR…

音频分割软件有什么?最方便的音频分割软件分享给你

一段长音频就像是一本厚重的百科全书&#xff0c;而音频剪辑师的任务&#xff0c;就是要将这本书拆分成数个章节&#xff0c;每章都有其独立的主题和内容&#xff0c;这非常考验剪辑师们的音频分割技巧。 幸运的是&#xff0c;随着技术的发展&#xff0c;市面上出现了许多优秀…