IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> vue多次缓存一个子页面(由keep-alive改变) -> 正文阅读

[JavaScript知识库]vue多次缓存一个子页面(由keep-alive改变)

我在一个页面中引入了一个子组件,我希望在父组件点击(按钮一)事件时切换子组件的值,并且在点击别的按钮(按钮二)的时候将当前子组件的属性保存下来。再点击之前的按钮(按钮一)将子组件还原成原始状态

这里需要你了解keep-alive 的工作原理,如果不懂也能一抹黑的用

组件完整代码:

<script>
export default {
  name: 'RKeepAlive',
  data() {
    return {
      vNode: null
    }
  },
  render: function(createElement) {
    if (this.vNode) {
      return this.vNode
    }
    return this.$slots.default[0]
  },
  created() {
    this.cache = Object.create(null)
    this.param = Object.create(null)
    this.keys = []
  },
  methods: {
    keepView(pid) {
      return new Promise(resolve => {
        const vNode = this.$slots.default[0]
        const { cache, keys, param } = this
        let id = vNode.elm.id
        if (id) {
          id = pid
        }
        const key = id
        const data = deepClone(vNode, this.$createElement)
        if (cache && cache[key]) {
          const len = keys.findIndex(x => x === key)
          if (len >= 0) {
            keys.splice(len, 1)
            keys.push(key)
          }
        } else {
          keys.push(key)
        }
        cache[key] = data
        param[key] = {
          data: JSON.parse(JSON.stringify(data.componentInstance._data)),
          props: JSON.parse(JSON.stringify(data.componentInstance._props))
        }
        vNode.data.keepAlive = true
      })
    },
    getView(pid) {
      let vNode = this.$slots.default[0]
      const { cache, param } = this
      const id = pid
      const key = id
      if (cache[key]) {
        this.vNode = Object.create(null)
        cache[key].componentInstance._data = JSON.parse(JSON.stringify(param[key].data))
        vNode = cache[key]
      }
      this.vNode = vNode
    },
    clearView() {
      this.vNode = null
    }
  }
}
function deepClone(vnode, createElement) {
  function cloneVNode(node) {
    const clonedChildren = node.children && node.children.map(vnode => cloneVNode(vnode))
    const cloned = createElement(node.tag, node.data, clonedChildren)
    cloned.text = node.text
    cloned.isComment = node.isComment
    cloned.componentOptions = node.componentOptions
    cloned.componentInstance = node.componentInstance
    cloned.elm = node.elm
    cloned.context = node.context
    cloned.ns = node.ns
    cloned.isStatic = node.isStatic
    cloned.key = node.key
    return cloned
  }
  const clonedVNodes = cloneVNode(vnode)
  return clonedVNodes
}
</script>

分析:

这是由vue 提供的一个渲染方法,当VueComponent发生变化时会带动render发生相应渲染
在这里采取了与keep-alive一致的方式,使用slot插入式

 render: function(createElement) {
    if (this.vNode) {
      return this.vNode
    }
    return this.$slots.default[0]
  },

初始化三个data

cache 用来存储this.$slots.default
param用来存储slot插槽中子组件的data
keys 在这里并没有用到,但是保留下来了

 created() {
    this.cache = Object.create(null)
    this.param = Object.create(null)
    this.keys = []
  },

这个方法是用来存储当前渲染的操作

keepView(pid) {
      return new Promise(resolve => {
        const vNode = this.$slots.default[0]
        const { cache, keys, param } = this
        let id = vNode.elm.id
        if (id) {
          id = pid
        }
        const key = id
        const data = deepClone(vNode, this.$createElement)
        if (cache && cache[key]) {
          const len = keys.findIndex(x => x === key)
          if (len >= 0) {
            keys.splice(len, 1)
            keys.push(key)
          }
        } else {
          keys.push(key)
        }
        cache[key] = data
        param[key] = {
          data: JSON.parse(JSON.stringify(data.componentInstance._data)),
          props: JSON.parse(JSON.stringify(data.componentInstance._props))
        }
        vNode.data.keepAlive = true
        console.log(this)
      })
    },

获取存储的渲染,并还原

这里需要做操作:this.vNode = Object.create(null),在这里是对VueComponent做一个欺骗,如果不进行欺骗vNode是null,VueComponent是不会发起对render的调用的

 getView(pid) {
      let vNode = this.$slots.default[0]
      const { cache, param } = this
      const id = pid
      const key = id
      if (cache[key]) {
        this.vNode = Object.create(null)
        cache[key].componentInstance._data = JSON.parse(JSON.stringify(param[key].data))
        vNode = cache[key]
      }
      this.vNode = vNode
    },

vnode的深度复制

function deepClone(vnode, createElement) {
  function cloneVNode(node) {
    const clonedChildren = node.children && node.children.map(vnode => cloneVNode(vnode))
    const cloned = createElement(node.tag, node.data, clonedChildren)
    cloned.text = node.text
    cloned.isComment = node.isComment
    cloned.componentOptions = node.componentOptions
    cloned.componentInstance = node.componentInstance
    cloned.elm = node.elm
    cloned.context = node.context
    cloned.ns = node.ns
    cloned.isStatic = node.isStatic
    cloned.key = node.key
    return cloned
  }
  const clonedVNodes = cloneVNode(vnode)
  return clonedVNodes
}

测试

做一个简单子组件

<template>
  <div>
    1231321
    <el-input v-model="input"></el-input>
    {{ids}}
  </div>
</template>
<script>
export default {
  name: 'TestView',
  props: {
    ids: {
      type: Number,
      default: 0
    }
  },
  data() {
    return {
      input: ''
    }
  }

}
</script>

测试代码

<el-button @click="test(true)"></el-button>
<el-button @click="test(false)"></el-button>
<el-button @click="test1(false)"> 更新</el-button>
<el-button @click="test2(false)"> 取2</el-button>
<el-button @click="test2(true)"></el-button>
<r-keep-alive ref="keepView">
 	<component :is="cop" :id="index" :ids="index" />
</r-keep-alive>

import RKeepAlive from '@/rewrite/r-keep-alive.vue'
import testView from '@/rewrite/test-view.vue'
export defalt{
	data() {
		return{    
		      index: 65535,
		      cop: 'test-view'
		}
	},
	methods: {
		test(item) {
	      console.log(item)
	      if (item) {
	       	// 存
	        this.$refs.keepView.keepView(this.index)
	      } else {
			// 取
	        this.$refs.keepView.getView(65535)
	        // this.index = 65535
	        // this.cop = 'test-view'
	      }
	    },
     	test2(item) {
	      if (!item) {
	        this.index = 65536
	        // this.$refs.keepView.clearView()
	      } else {
	        this.$refs.keepView.getView(65536)
	      }
	    },
	    test1() {
	      this.index = 65536
	      // this.cop = 'test-viewi'
	    },
	}
}

在这里插入图片描述

最终展示效果

在这里插入图片描述

操作 :
1 在输入框输入: 123
2. 点击存
3. 点击更新 ,从新输入: 321
4. 点击存
5. 点击取(出现 id=65535存的数据)
在这里插入图片描述

  1. 点击清 (出现id= 65536存的数据)
    在这里插入图片描述
    说明:
    这是基于vue2 的,vue3没测不知道好不好用
    在取值时候一定要先欺骗组件更新了,否则不会过
    在同一个子组件的时候this. s l o t s . d e f a u l t [ 0 ] . c o m p o n e n t I n s t a n c e 无论如何都是会改变的,所以选择了使用 p a r a m 在取得时候做替换 t h i s . slots.default[0].componentInstance无论如何都是会改变的,所以选择了使用param在取得时候做替换 this. slots.default[0].componentInstance无论如何都是会改变的,所以选择了使用param在取得时候做替换this.slots.default[0].componentInstance的_props 与prarm.prop之间是不能赋值的,如果赋值,VueComponent不会刷新

最后

本人是全栈,对前端也是一知半解,欢迎大佬来更新方法

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-24 20:47:38  更:2022-09-24 20:48:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 9:34:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码