vue組件數據改變但是組件不刷新怎么辦(關于v-show)

今天寫項目時遇到了一個坑,情景描述如下:
用v-for創建了8個li,每個li都有一個類按鈕(下文就稱之為按鈕),點擊該按鈕時,e.target的背景圖片發生變化,再點擊該按鈕e.target的背景圖片又恢復成初始狀態,如此循環。
未點擊時效果圖:


初始狀態.png

點擊后:


第一次點擊后.png

如果只是用js,很容易解決,可在vue組件中并非如此了。
開始的時候,只寫了一個控件來切換背景圖片,但是類似于this.item=!this.item表達式并不能如愿切換。
然后就寫了兩個控件,不同控件不同背景圖,在設置樣式時讓他們重疊,通過v-show指令來決定顯示哪個控件。在這里,v-show監控的值也是變化的。這樣對用戶來說,“還是一個按鈕”。然而結果卻是,數據如愿改變,dom元素的樣式并沒有隨之變化。具體就是第二個控件顯示的v-show的值始終不變。無論怎么修改數據(data,computed...),我自巋然不變,崩潰啊。
貼代碼吧:
html部分:

<ul class="selectmenu">
                        <li v-for="(item,index) in createAccount.menu" class="col-md-3 col-xs-6" :key="index" :v-model="index">
                            <div class="item">
                                <div class="pic">
                                    <img :src="'image/account/'+item.img" alt="">
                                    <span v-show="unchecked[index]" :data-idx="index" class="selected" :style="selectStyle" @click="changeStyle()"></span>
                                    <span v-show="unchecked[index]"  :data-idx="index"  class="selected" :style="selectedStyle" @click="changeStyle1()"></span>
                                </div>
                                <p>{{item.text}}</p>
                                <div v-show="item.ishelp" class="help">
                                    <span>?</span>
                                    <p v-show="item.helptext" class="helptext">{{item.helptext}}</p>
                                </div>  
                            </div>
                        </li>
                    </ul>

js部分:

var CreateAccount={
    template:"#tpl_createAccount",
    data:function(){
        return {
            createAccount:{},
            selectStyle:{
                backgroundImage:'url(../image/account/icon_checkmark.png)',
                backgroundPosition:'center center',
                backgroundSize:'auto 100%',
                backgroundRepeat:'no-repeat'
            },
            selectedStyle:{
                backgroundImage:'url(../image/account/icon_checkmark_selected.png)',
                backgroundPosition:'center center',
                backgroundSize:'auto 100%',
                backgroundRepeat:'no-repeat'
            }
        }
    },
    computed:{
        unchecked:function(){
            return [true,true,true,true,true,true,true,true]
        },
        checked:function(){
            return [false,false,false,false,false,false,false,false]
        }
    },
    created:function(){
        this.$http.get("data/createaccount.json")
        .then(function(res){
            this.createAccount=res.data.data;
        });
    },
    methods:{
        changeStyle:function(e){
            var e=event||window.event;
            var tar=e.target.getAttribute("data-idx");
            Vue.set(this.unchecked,tar,false);
            Vue.set(this.checked,tar,true);
        },
        changeStyle1:function(e){
            var e=event||window.event;
            var tar=e.target.getAttribute("data-idx");
            Vue.set(this.unchecked,tar,true);
            Vue.set(this.checked,tar,false);
        }
    }
};

css就省略了。
絞盡腦汁,想到v-show的本質就是通過設置display:none實現元素的顯隱,盡然這里v-show沒辦法做到,那就直接控制元素的display值吧。
于是改變代碼:
html去掉v-show這一部分,如下:

<ul class="selectmenu">
                        <li v-for="(item,index) in createAccount.menu" class="col-md-3 col-xs-6" :key="index" :v-model="index">
                            <div class="item">
                                <div class="pic">
                                    <img :src="'image/account/'+item.img" alt="">
                                    <span :data-idx="index" class="selected" :style="selectStyle" @click="changeStyle()"></span>
                                    <span  :data-idx="index"  class="selected" :style="selectedStyle" @click="changeStyle1()"></span>
                                </div>
                                <p>{{item.text}}</p>
                                <div v-show="item.ishelp" class="help">
                                    <span>?</span>
                                    <p v-show="item.helptext" class="helptext">{{item.helptext}}</p>
                                </div>  
                            </div>
                        </li>
                    </ul>

js則在樣式里添加上display,如下:

var CreateAccount={
    template:"#tpl_createAccount",
    data:function(){
        return {
            createAccount:{},
            selectStyle:{
                display:"block",
                backgroundImage:'url(../image/account/icon_checkmark.png)',
                backgroundPosition:'center center',
                backgroundSize:'auto 100%',
                backgroundRepeat:'no-repeat'
            },
            selectedStyle:{
                display:"none",
                backgroundImage:'url(../image/account/icon_checkmark_selected.png)',
                backgroundPosition:'center center',
                backgroundSize:'auto 100%',
                backgroundRepeat:'no-repeat'
            }
        }
    },
    computed:{
        unchecked:function(){
            return [true,true,true,true,true,true,true,true]
        },
        checked:function(){
            return [false,false,false,false,false,false,false,false]
        }
    },
    created:function(){
        this.$http.get("data/createaccount.json")
        .then(function(res){
            this.createAccount=res.data.data;
        });
    },
    methods:{
        changeStyle:function(e){
            var e=event||window.event;
            var tar=e.target.getAttribute("data-idx");
            Vue.set(this.unchecked,tar,false);
            Vue.set(this.checked,tar,true);
            this.selectStyle.display="none";
        },
        changeStyle1:function(e){
            var e=event||window.event;
            var tar=e.target.getAttribute("data-idx");
            Vue.set(this.unchecked,tar,true);
            Vue.set(this.checked,tar,false);
            this.selectStyle.display="block";
        }
    }
};

問題解決了嗎?——————答案是:沒-----有!
先不管樣式是否完整,首先上述js代碼中this.selectStyle依舊是組件中的全局變量,也就是會影響到所有的li里面的按鈕,而并非僅僅是e.target。
再想辦法吧!要改變的僅僅是e.target的。
直接設置e.target.style的值?當然啦,然而這里style要提前定義一下,不然會提醒你style未定義。
然后因為是兩個span,一個是e.target,一個是e.target的替身(它的兄弟元素),需要把這個替身獲取到。
中間過程省略,太傷心。
后來只是修改了js部分:

var CreateAccount={
    template:"#tpl_createAccount",
    data:function(){
        return {
            style:null,
            createAccount:{},
            selectStyle:{
                display:"block",
                backgroundImage:'url(../image/account/icon_checkmark.png)',
                backgroundPosition:'center center',
                backgroundSize:'auto 100%',
                backgroundRepeat:'no-repeat'
            },
            selectedStyle:{
                display:"none",
                backgroundImage:'url(../image/account/icon_checkmark_selected.png)',
                backgroundPosition:'center center',
                backgroundSize:'auto 100%',
                backgroundRepeat:'no-repeat'
            }
        }
    },
    computed:{
        unchecked:function(){
            return [true,true,true,true,true,true,true,true]
        },
        checked:function(){
            return [false,false,false,false,false,false,false,false]
        }
    },
    created:function(){
        this.$http.get("data/createaccount.json")
        .then(function(res){
            // console.log(res.data);
            this.createAccount=res.data.data;
        });
    },
    methods:{
        changeStyle:function(e){
            var e=event||window.event;
            var el=e.target;
            var tar=e.target.getAttribute("data-idx");
            var next=$(el).next()[0];
            Vue.set(this.unchecked,tar,false);
            Vue.set(this.checked,tar,true);
            e.target.style=this.selectStyle;
            e.target.style.display="none";
            next.style=this.selectedStyle;
            next.style.display="block";
            next.style.backgroundImage='url(../image/account/icon_checkmark_selected.png)',
            next.style.backgroundPosition='center center',
            next.style.backgroundSize='auto 100%',
            next.style.backgroundRepeat='no-repeat'
            this.selectStyle=next.style;
            // this.selectedStyle.display="block";
        },
        changeStyle1:function(e){
            var e=event||window.event;
            var el=e.target;
            var tar=e.target.getAttribute("data-idx");
            var pre=$(el).prev()[0];
            Vue.set(this.unchecked,tar,true);
            Vue.set(this.checked,tar,false);
            e.target.style=this.selectedStyle;
            pre.style.display="block";
            pre.style.backgroundImage='url(../image/account/icon_checkmark.png)',
            pre.style.backgroundPosition='center center',
            pre.style.backgroundSize='auto 100%',
            pre.style.backgroundRepeat='no-repeat'
            this.selectedStyle=pre.style;
        }
    }
};

很麻煩吧!我也覺得。曾嘗試著刪除一部分看似能刪除的代碼,結果是不能刪。
你以為這樣問題就解決了嗎?只是解決了一部分。
第一次點擊和第二次點擊都沒有問題(忽略那個報錯吧,還木有想到辦法避免,重要的是想要的結果出來了),但是第三次第四次點擊的時候就沒有效果啦。。。。。。問題出在哪里呢?就是第三次點擊的時候e.target沒有如愿變成第一個span,而且第一個span沒有了樣式。

....好吧,我能說在發布完文章后,我又去修改了一下代碼,僅僅只是加了一行代碼而已,問題就解決了嗎?淚崩!

changeStyle1:function(e){
            var e=event||window.event;
            var el=e.target;
            var tar=e.target.getAttribute("data-idx");
            var pre=$(el).prev()[0];
            Vue.set(this.unchecked,tar,true);
            Vue.set(this.checked,tar,false);
            e.target.style=this.selectStyle;
            e.target.style.display="none";
            pre.style=this.selectedStyle;
            pre.style.display="block";
            pre.style.backgroundImage='url(../image/account/icon_checkmark.png)',
            pre.style.backgroundPosition='center center',
            pre.style.backgroundSize='auto 100%',
            pre.style.backgroundRepeat='no-repeat'
        }

就是那行e.target.style.display="none";
不過呢,還是覺得很麻煩,這些代碼基本都是缺什么就添加什么添出來的。有沒有小伙伴有更簡單的辦法呢?求分享咯!
————————————————————————————————
后來的優化:
http://www.lxweimin.com/p/4fe1f4d90a5d

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標簽默認的外補...
    _Yfling閱讀 13,796評論 1 92
  • 1.從載入EasyUI開始 讀者需要到EasyUI官網中下載包含原文件和demo的壓縮包,并解壓到之前編寫的代碼目...
    老皮丘閱讀 1,768評論 0 6
  • 1. tab列表折疊效果 html: 能源系統事業部 崗位名稱: 工作地點 崗位名...
    lilyping閱讀 1,899評論 0 1
  • 圖/網絡 現在很多人經常掛在嘴邊的詞便是“迷茫”,“頹廢”。 有人說,人生不是計算題,沒有標準的答案,所以處處充...
    夏至星輝閱讀 503評論 0 2
  • 今天是8月30號,星期三,農歷七月初九。和往常一樣,五點多就醒了。今天我晨運的地點和往常不一樣。他就是在廣東省英德...
    曾心想事成閱讀 171評論 0 1