vuejs 解决数组子组件,在子组件相同情况下,splice更换或删除数组数据,组件不刷新,组件外能刷新的问题

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>电子答题卡</title>
    <link rel="stylesheet" href="css/answer_card.css">
</head>
<body >
<div v-cloak class="answerCard" id="answerCard">
    <div class="choicetype clearfix">
        <div class="addtype">
            <span>添加题型</span>
            <a  v-for="(item,index) in classData" 
                v-on:click="clicktype(item,index)" 
                href="#">
                +{{item.radiotopic}}
            </a>
        </div>
    </div>
    <div class="questiontype" v-for="(item,index) in newData">
        <div class="question " v-bind:class="addClassState(item)">
            <div class="title clearfix" v-on:click="isOpne(item,index)">
                <div class="sort">
                    <em>题型排序</em>
                    <span><i class="up" v-bind:class="{noup: index==newData.length-1}" v-on:click.stop="upClick(item,index)"></i><i class="down" v-bind:class="{nodown: index==0}" v-on:click.stop="downClick(item,index)"></i><a href="javascript:void(0)" class="del"  v-on:click.stop="delClick(item,index)"></a></span>
                </div>
            </div>
            <component :is="curComponentFn(item)" :key="item.guid" v-bind:oitem="item" v-bind:class="{open:activeOpen==index}" v-bind:onewdata="newData" v-bind:oindex="index" ></component>
        </div>
    </div>
</div>
<script type="text/javascript" src="js/lib/jquery.min.js"></script>
<script type="text/javascript" src="js/lib/es6-promise.auto.min.js"></script>
<script type="text/javascript" src="js/lib/axios.min.js"></script>
<script type="text/javascript" src="js/lib/vue.min.js"></script>
<script type="text/javascript" src="js/base.js"></script>
<script type="text/javascript" src="js/app/testKey.js"></script>
</body>
</html>
html
复制代码
复制代码
var oData={
    timelimit:0,  //设置时间
    istime:true,    //是否设置时间开关
    allWrongNum:0,    //错题数
    countDown:0,  //倒计时
    activeIndex: -1, //题型当前选中
    activeOpen:0,    //当前选中题型展开
    curComponent:"", //加展相应组件
    classData:[],   //记录题型数据
    newData:[],  //得到新的数据(用于编辑POST)
    getData:[],  //得到新的数据(用于GET)
}

// 注册组件4
var custom4=Vue.component('custom4', {
    props: ["oitem","onewdata","oindex"],
    data:function(){
        return {
            odata:this.oitem,
            list: [],
            anewdata:this.onewdata,
            aindex:this.oindex,
            asortnum:[],
        }
    },
    template: '<div class="cont">'+
                    '<ul class="clearfix">'+
                        '<li v-for="(oitemli,index) in creadData">'+
                            '<em>{{(index+1)+asortnumHandler}}.</em>'+
                            '<p>'+
                                '<input type="text"  v-for="(oitemspan,index1) in oitemli.selected" placeholder="参考答案" v-model=oitemspan  v-on:keyup.self="addOn(oitemspan,index,index1)" v-bind:class="{on:oitemspan!=\'\'}"/>'+
                            '</p>'+
                        '</li>'+
                    '</ul>'+
                '</div>',
    computed: {
        creadData:function(){
            this.list=[];
            this.creadDaan();
            for(var i=0;i<this.odata.num;i++){
                var c=this.creatAnswer(parseInt(this.odata.option))
                for(var m=0;m<c.length;m++){
                    var oindex=this.odata.answer[i].text[m];
                    c.splice(m, 1);
                    c.splice(m, 0, oindex);
                }
                var item = {
                    selected: c,
                }

                this.list.push(item)
            }
            return this.list
        },
        sortNumHandler:function(){
               var alln=[];
               for(var i=0;i<this.anewdata.length;i++){
                   alln.push(this.anewdata[i].num)
               }
               this.asortnum=alln
               return this.asortnum
        },
           asortnumHandler:function(){
               var ao=0;
               if(this.aindex==0){
                ao=0;
                return ao
            }
               for(var i=0;i<this.sortNumHandler.length;i++){    
                   ao+=parseInt(this.sortNumHandler[i])
                   if(i==this.aindex-1){
                       return ao
                   }
               }
           }
   },
    methods:{
        creatAnswer:function(n){ //生成答案
            var letter=[];
            for(var i=0;i<n;i++)
            {
                letter.push("");
            }
            return letter;
        },
        creadDaan:function(index){
            var c = this.creatAnswer(parseInt(this.odata.option))
            var createLength=this.odata.num-this.odata.answer.length;
            for (var i = 0; i < createLength; i++) {
                var n={text:c}
                this.odata.answer.push(n)
            }
            return this.odata.answer    
        },
    },
    created: function() {
        this.creadDaan();
    }
})

// 注册组件5
var custom5=Vue.component('custom5', {
    props: ["oitem","onewdata","oindex"],
    data:function(){
        return {
            odata:this.oitem,
            list: [],
            anewdata:this.onewdata,
            aindex:this.oindex,
            asortnum:[],
            handPop: -1,
            keepCanvas:null
        }
    },
    template: '<div class="cont look_subjective" id="look_subjective">'+
                    '<ul class="clearfix">' +
                        '<li v-bind:id="\'subjective\'+(index + 1)" v-for="(oitemli,index) in creadData">'+
                            '<em>{{(index+1)+asortnumHandler}}.</em>'+
                             '<div class="upload" v-bind:class="{on:oitemli.options.tit!=\'\'||oitemli.options.img!=\'\'}" >'+
                                '<p class="tit" >'+
                                    '<textarea  type="text" maxlength="400" v-model="oitemli.options.tit" v-on:keyup.self="addTit(oitemli.options.tit,index)" placeholder="请编辑文字" />' +
                                '</p>'+
                                '</div>'+
                            '</div>'+
                        '</li>'+
                    '</ul>'+
                '</div>',
    computed: {
        creadData:function(){
            this.list=[];
            this.creadDaan();
            for(var i=0;i<this.odata.num;i++){
                var item = {
                    options: this.odata.answer[i],
                }
                this.list.push(item)
            }
            return this.list
        },
        sortNumHandler:function(){
               var alln=[];
               for(var i=0;i<this.anewdata.length;i++){
                   alln.push(this.anewdata[i].num)
               }
               this.asortnum=alln
               return this.asortnum
        },
           asortnumHandler:function(){
               var ao=0;
               if(this.aindex==0){
                ao=0;
                return ao
            }
               for(var i=0;i<this.sortNumHandler.length;i++){    
                   ao+=parseInt(this.sortNumHandler[i])
                   if(i==this.aindex-1){
                       return ao
                   }
               }
           }
    },
    methods:{
        creadDaan: function (index) {
            var createLength = this.odata.num - this.odata.answer.length;
            for (var i = 0; i < createLength; i++) {
                var n = { tit: '', img: [] }
                this.odata.answer.push(n)
            }
            return this.odata.answer
        },
        },

    created: function() {
        this.creadDaan();
    },
})
  
  
var editApp=new Vue({
    el:'#answerCard',
    data:oData,
    filters:{//过滤器
        numChinese: function (n) {  //提供中文数字
            var cnum = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
            var s = '';
            n = n + 1;
            var tenNum =parseInt(n / 10);
            var units = n % 10;
            if (tenNum === 1)
                s += "十";
            else if (tenNum > 1)
                s += cnum[tenNum] + "十";
            if (units > 0)
                s += cnum[units];
            return s;
        } 
   },
    methods:{
        newDataFn:function(idata){  //根据state生成数据
            this.newData=[];
            if(idata){
                for (var n = 0; n < idata.length; n++) {
                    this.newData.push(idata[n])
                }
            return this.newData
            }
          },
        clicktype: function (todo, index) { //选择题型
            //todoPop(todo);
            todo.guid = guid();
            this.newData.push(JSON.parse(JSON.stringify(todo)));
            this.activeOpen = this.newData.length - 1;
        },



        isOpne:function(todo,index){  //组件按需展开
            for(var i=0;i<this.newData.length;i++){
                this.activeOpen=index;
            }
        },
        delClick:function(todo,index){  //删除题型    
            this.newData.splice(index, 1);
            //var sss= JSON.parse(JSON.stringify(this.newData));
            //this.newData = null;
            //this.newData = sss;
        },
        upClick:function(todo,index){   //排序向下
              if(index==this.newData.length-1){
                  return
              }
              var ss = this.newData.splice(index, 1);
              //var newss = JSON.parse(JSON.stringify(ss));
              this.newData.splice(index + 1, 0, ss[0]);
              //this.$set(this.newData, index + 1, ss[0]);
              //Vue.set(this.newData, index + 1, ss[0])
            this.isOpne(todo,index)    
          },
          downClick:function(todo,index){ //排序向上
              if(index==0){
                  return
              }
              var ss=this.newData.splice(index, 1);
              this.newData.splice(index-1, 0, ss[0]);
              this.isOpne(todo,index)    
          },
          addClassState:function(todo){    //自动生成题数类型加class
              if(todo.radioid=="itemFill"){
                  return {itemFill:true}
              }
              if(todo.radioid=="itemSubjective"){
                  return {itemSubjective:true}
              }
          },
        curComponentFn:function(todo){
              if(todo.radioid=="itemFill"){
                  return "custom4"
              }
              if(todo.radioid=="itemSubjective"){
                  return "custom5"
              }
        },
        innt:function(){ //初始化渲染页面
              this.newDataFn(this.getData)
        },
    },
    created: function() {
          var _this=this;
               _this.getData = [];
var classStr="[{\"guid\":null,\"radiotopic\":\"填空题\",\"radioid\":\"itemFill\",\"isselect\":true,\"num\":\"1\",\"option\":\"1\",\"fraction\":\"1\",\"answer\":[]},{\"guid\":null,\"radiotopic\":\"主观题\",\"radioid\":\"itemSubjective\",\"isselect\":true,\"num\":\"1\",\"option\":\"1\",\"fraction\":\"1\",\"answer\":[]}]"; 
               var classtype = JSON.parse(classStr);
_this.classData = classtype ;
            _this.innt()
            
    }
    
    
})

//生成guid ,解决排序
function guid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
    });
}

//选择题型弹出层
function todoPop(todo){
    alert(todo.radiotopic+"弹出层")
    var mydata={
        "num":"4",
        "option":"4",
        "fraction":"10",
    }
    todo.num=mydata.num;
    todo.option=mydata.option;
    todo.fraction=mydata.fraction;
}


//获取class
function getByClass(clsName, parent){         
    var oCls=parent.getElementsByTagName('*')//获取所有的标签元素
    var arr=[];
    for(i in oCls){
    //对遍历的标签元素与要查找的元素进行判断
        if(oCls[i].className==clsName){
            arr.push(oCls[i])
        }
    }
    return arr
}
js
复制代码

var ss = this.newData.splice(index, 1);
this.newData.splice(index + 1, 0, ss[0]);

通过splice进行数组切换后发现,组件内视图没有刷新,但外面的标题刷新了,如下图。

  添加2个主观题 

数组改变后

 

原因是vue内部组件缓存机制导致的。,解决方案:为每个组件添加key, 下图是官方解释

 

 

<component :is="curComponentFn(item)" :key="item.guid" v-bind:oitem="item" v-bind:class="{open:activeOpen==index}" v-bind:onewdata="newData" v-bind:oindex="index" ></component>

去掉 :key="item.guid" 就会重现

 

demo https://pan.baidu.com/s/1cCqsnO

posted @   莫欺  阅读(6695)  评论(1编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示