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

news2024/12/1 0:48:22

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

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

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

相关文章

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

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

stl容器适配器 stack与queue,priority_queue

目录 一.stack 1.stack的使用 2.适配器 3.stack相关的题目 最小栈. - 力扣&#xff08;LeetCode&#xff09; ​编辑 栈的弹出压入序列栈的压入、弹出序列_牛客题霸_牛客网 用两个栈实现队列. - 力扣&#xff08;LeetCode&#xff09; 4.stack的模拟实现 二.queue队列…

一起学习LeetCode热题100道(48/100)

48.路径总和 III(学习) 给定一个二叉树的根节点 root &#xff0c;和一个整数 targetSum &#xff0c;求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始&#xff0c;也不需要在叶子节点结束&#xff0c;但是路径方向必须是向下的&#xff08;只…

前端获取主流浏览器的信息进行判断 实现自适应内容(360浏览器)

我一般都是用谷歌浏览器进行开发&#xff0c;在开发大屏可视化的时候出现了浏览器不适应的问题&#xff0c;需要不同的浏览器进行判断&#xff0c;360返回 Chrome 内核&#xff0c; 获取的信息无法跟谷歌浏览器区别 这个是中国的主流浏览器&#xff1a; 比如谷歌可以正常显示&…

十要素超声波气象传感器

十要素微型气象传感器&#xff08;也称为全要素微型气象传感器&#xff09;通常具有以下几个基本功能&#xff1a; 温度测量&#xff1a;测量环境的温度&#xff0c;并提供实时温度数据。 湿度测量&#xff1a;测量环境的湿度水平&#xff0c;并提供实时湿度数据。 大气压力测…

【安全靶场】-DC-5

❤️博客主页&#xff1a; iknow181&#x1f525;系列专栏&#xff1a; 网络安全、 Python、JavaSE、JavaWeb、CCNP&#x1f389;欢迎大家点赞&#x1f44d;收藏⭐评论✍ 一、收集信息 1.用burp测试穷尽文件名 使用两个字典 发现footer页面 可能存在文件包含&#xff0c;因为co…

记一次 MIGO 短缺BA 非限制使用 35,713.970 USD : 100002919-Z040 100Z 1000 99991231

mb52数量 一想到该物料的启用了批次管理 &#xff0c; 应该去查一下 批次管理的底表 MCHB &#xff08;各种库存地表见 SAP MM 库存分类及对应的存储表-CSDN博客&#xff09; 实际调用migo的参数 这下明确了&#xff0c;总共一起60000多是足够调出的&#xff0c;但是99991231这…

zabbix通过snmp监控物理服务器硬件信息

背景&#xff1a;公司的华三服务器周末的时候市电跳闸&#xff0c;监控没有设置告警&#xff0c;幸好有UPS供电&#xff0c;工作日发现问题后市电恢复。 方法&#xff1a; 1、登陆物理服务器带外&#xff0c;开放snmp并设置团体名 2、找一台安装了nmap的机器&#xff0c;查看…

python使用gurobi用法解析和案例

文章目录 1. Gurobi Python接口的基本使用2. 变量类型3. 目标函数4. 约束条件5. 模型求解和结果分析6. 常见注意事项7. gurobi代码示例 1. Gurobi Python接口的基本使用 在Python中使用Gurobi进行优化&#xff0c;通常需要按以下步骤操作&#xff1a; 导入Gurobi包 &#xff…

【Java】—— 使用Java在控制台实现海豚记账软件

目录 1. 项目背景 2. 代码思路 2.1 主要功能 2.2 数据结构 2.3 控制流程 3. 实现步骤 3.1 初始化变量 3.2 显示菜单 3.3 处理用户输入 3.4 退出程序 4. 知识点解析 4.1 Scanner类 4.2 字符与数字转换 4.3 循环与条件判断 5.完整代码 6.运行结果展示 1. 项目背景…

【秋招笔试】8.18字节跳动秋招(第一场)-三语言题解

🍭 大家好这里是 春秋招笔试突围,一起备战大厂笔试 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 编程一对一辅导 ✨ 本系列打算持续跟新 春秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸 ✨ 笔试合集传送们 -> 🧷春秋招笔试合集 🍒 本专栏已收…

IOS 12 自定义用户协议对话框

实现效果 实现逻辑 本文使用QMUI里面提供的控制器 自定义控件 实现。 添加依赖 #腾讯开源的UI框架&#xff0c;提供了很多功能&#xff0c;例如&#xff1a;圆角按钮&#xff0c;空心按钮&#xff0c;TextView支持placeholder #https://github.com/QMUI/QMUIDemo_iOS #http…

《向量数据库指南》——解决方案:采用安全、高性能的Milvus Cloud向量数据库,赋能Dopple AI的创新与发展

解决方案:采用安全、高性能的Milvus Cloud向量数据库,赋能Dopple AI的创新与发展 在当今这个数据驱动的时代,向量数据库作为机器学习、人工智能等领域的重要基础设施,正发挥着越来越关键的作用。对于Dopple AI这样一个致力于创新的前沿团队来说,选择一个合适的向量数据库…

盘点8大跨境电商平台发展前景及选品分析(亚马逊、速卖通篇)

跨境电商行业在全球范围内持续发展&#xff0c;各大平台各有特色&#xff0c;针对不同的市场和消费者群体提供多元化的服务。以下是亚马逊、Shopee、TikTok、TEMU、速卖通、eBay、Lazada、SHEIN这八大跨境电商平台的背景、主要针对群体、消费者购物偏好及选品建议的简要介绍&am…

C语言:函数详解(1)

目录 一、函数的概念 二、库函数 三、自定义函数 3.1 函数的语法形式 3.2 函数的举例 四、形参和实参 4.1 实参 4.2 形参 4.3 实参与形参的关系 一、函数的概念 数学中我们其实就见过函数的概念&#xff0c;比如&#xff1a;⼀次函数 ykxb &#xff0c;k和b都是常数&am…

[Meachines] [Easy] Buff Gym-CMS-RCE+Chisel端口转发+CloudMe云文件存储-缓冲区溢出权限提升

信息收集 IP AddressOpening Ports10.10.10.198TCP:7680,8080 $ nmap -p- 10.10.10.198 --min-rate 1000 -sC -sV -Pn PORT STATE SERVICE VERSION 7680/tcp open pando-pub? 8080/tcp open http Apache httpd 2.4.43 ((Win64) OpenSSL/1.1.1g PHP/7.4.6) |…

力扣:移动零

文章目录 需求分析优化下双指针结尾 需求 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,1…

中国平安银行笔试考什么?及如何通过平安测评|附真题库面试攻略

一、中国平安银行公司介绍 中国平安银行&#xff0c;作为中国金融领域的重要力量&#xff0c;以其雄厚的实力和创新的金融服务在行业内脱颖而出。平安银行依托中国平安集团的强大资源&#xff0c;致力于为客户提供全方位的金融解决方案。 平安银行拥有广泛的业务网络&#xff0…

堆排序的插入和删除

插入&#xff1a; 1. 检查你的顺序表是否还有位置去插入&#xff0c;如果没有需要扩展 2. 插入到已有序列的后一位置 3. 和其父节点进行比较&#xff0c;是否满足大根堆/小根堆规则 4. 不满足则需要交换数值 删除&#xff1a; 1. 将最后一个元素覆盖将要删除的元素&#xff0…

第八季完美童模全球十佳人气超模【许馨予】荣耀加冕 见证星芒风采!

7月20-23日&#xff0c;2024第八季完美童模全球总决赛在青岛圆满落幕&#xff0c;在盛大的颁奖典礼上&#xff0c; 全球观众网友通过现场参与和网络直播的方式&#xff0c;见证了一位人气榜样的诞生&#xff01;在众多优秀的小超模中&#xff0c;性格开朗的10岁女孩许馨予从本次…