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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM