1. 程式人生 > >在django中使用vue.js需要注意的地方

在django中使用vue.js需要注意的地方

有介面如下:

  http://127.0.0.1:8000/info/schemes/

  返回json資料:

[
    {
        "name": "(山上雙人標準間)黃山經典二日遊(魅力黃山,日出雲海,人間仙境,春暖花開)", 
        "day": 2, 
        "night": 1, 
        "favorites": 0, 
        "score_avg": 4, 
        "photo_url": "/media/images/scenic/a9836502.jpg", 
        "review_num": 2, 
        "unit_price": 0
    }, 
    {
        "name": "0購物+三環內接!鄭州—焦作雲臺山二日遊,含1晚住宿+1早2正餐,無強制消費", 
        "day": 2, 
        "night": 1, 
        "favorites": 0, 
        "score_avg": 4, 
        "photo_url": "/media/images/scenic/3a82e902.jpg", 
        "review_num": 1, 
        "unit_price": 329
    }, 
    {
        "name": "島內酒店上門接>廈門至泉州開元寺+南少林+洛陽橋+西街+天后宮一日遊", 
        "day": 1, 
        "night": 0, 
        "favorites": 0, 
        "score_avg": 4, 
        "photo_url": "/media/images/scenic/f8106f02.jpg", 
        "review_num": 2, 
        "unit_price": 0
    }, 
    {
        "name": "南寧✈西安兵馬俑華清池延安黃帝陵壺口瀑布城牆5日/耳麥自助餐/0購物/接送機", 
        "day": 5, 
        "night": 4, 
        "favorites": 0, 
        "score_avg": 4, 
        "photo_url": "/media/images/scenic/93835fbb.jpg", 
        "review_num": 1, 
        "unit_price": 3045
    }, 
    {
        "name": "北京+天津純玩6日遊/餐餐特色/連鎖酒店/專車專導/故宮/瓷房子贈升國旗", 
        "day": 6, 
        "night": 5, 
        "favorites": 0, 
        "score_avg": 4, 
        "photo_url": "/media/images/scenic/0f.water.jpg", 
        "review_num": 1, 
        "unit_price": 0
    }, 
    {
        "name": "住蒙古包>內蒙古希拉穆仁草原+響沙灣沙漠+成吉思汗陵+呼和浩特市內雙飛五日遊", 
        "day": 5, 
        "night": 4, 
        "favorites": 0, 
        "score_avg": 4, 
        "photo_url": "/media/images/scenic/4b806602.jpg", 
        "review_num": 1, 
        "unit_price": 0
    }, 
    {
        "name": "北京全景高階五星遊丨餐餐特色&0購物0自費&24H接送&贈德雲社+人民大會堂", 
        "day": 5, 
        "night": 4, 
        "favorites": 0, 
        "score_avg": 4, 
        "photo_url": "/media/images/scenic/ca841f56.jpg", 
        "review_num": 1, 
        "unit_price": 0
    }, 
    {
        "name": "機票+含餐>西安兵馬俑/華清池/驪山/西嶽華山/延安/黃帝陵/壺口瀑布6日", 
        "day": 6, 
        "night": 5, 
        "favorites": 0, 
        "score_avg": 4, 
        "photo_url": "/media/images/scenic/93835fbb.jpg", 
        "review_num": 1, 
        "unit_price": 2740
    }, 
    {
        "name": "高鐵/動車往返>寧波—溫州雁蕩山2日遊 淨名谷+靈巖景區+大龍湫 賞靈峰夜景", 
        "day": 2, 
        "night": 1, 
        "favorites": 0, 
        "score_avg": 4, 
        "photo_url": "/media/images/scenic/7565abdd.jpg", 
        "review_num": 1, 
        "unit_price": 0
    }
]

 

通過vue去請求這個api,並將資料遍歷,生成多個div塊模板,並渲染資料,效果圖如下:

api 返回json中有9條記錄,所以對應應該生成9個上圖的div塊,開始動手:

首先,在html頁面上引入js

<script type="text/javascript" src="{% static 'js/vue.js' %}"></script>
<script type="text/javascript" src="{% static 'js/axios.min.js' %}"></script>
<script type="text/javascript" src="{% static 'js/common.js' %}"></script>
<script>
$(document).ready(function () {
  getHotScheme();                             1. 在dom載入完之後執行getHotScheme函式
});
</script>

要用到vue就少不vue.js,Vue.js 2.0 版本推薦使用 axios 來完成 ajax 請求。

我們將上面功能的實現寫在common.js的getHotScheme中

相關html如下:

            <div class="GridLex- gap-30-wrappper package-grid-item-wrapper">

                <div class="GridLex-grid-noGutter-equalHeight" id="scheme_app">

                    <template v-for="schemeInfo in schemesInfo">
                        <div class="GridLex-col-4_sm-6_xs-12 mb-30">
                            <div class="package-grid-item">
                                <a href="detail-page.html">
                                    <div class="image">
                                        <img :src="schemeInfo.photo_url" alt="Tour Package"/>

                                        <div class="absolute-in-image">
                                            <div class="duration"><span>{{ schemeInfo.day }} 天 {{ schemeInfo.night }} 夜</span></div>
                                        </div>
                                    </div>
                                    <div class="content clearfix">
                                        <h5>{{ schemeInfo.name }}</h5>

                                        <div class="rating-wrapper">
                                            <div class="raty-wrapper">
                                                <div class="star-rating-read-only" v-bind:data-rating-score="schemeInfo.score_avg"></div>
                                                <span> / {{ schemeInfo.review_num }} 評論</span>
                                            </div>
                                        </div>
                                        <div class="absolute-in-content">
                                            <span class="btn"><i class="fa fa-heart-o"></i></span>

                                            <div class="price">¥{{ schemeInfo.unit_price }}</div>
                                        </div>
                                    </div>
                                </a>
                            </div>
                        </div>
                    </template>

                </div>

            </div>

js:getHotScheme

function getHotScheme(){
    new Vue({
        el: '#scheme_app',
        data () {
            return {
            schemesInfo: null
            }
        },
        mounted () {
            axios
            .get('/info/schemes')
            .then(response => (this.schemesInfo = response.data))
            .catch(function (error) { // 請求失敗處理
                console.log(error);
            });
        }
    })
}

解釋一下:

  getHotScheme()在DOM載入後執行,其中建立了vue物件,el表示vue的作用範圍,它被繫結到了html中的id為scheme_app的div,data中我們需要使用schemesInfo,初始為null,當axios請求成功之後,schemesInfo的值為api的返回的json

  在html中:

  我們要遍歷schemesInfo資料,在需要重複生成的div塊外新增 template ,<template v-for="schemeInfo in schemesInfo">````````</template>

  被template標籤包含的內容將被生成多份,text部分通過{{}}取資料進行渲染,但是在標籤屬性中使用資料需要做出修改:比如img標籤,指定src時不應該使用<img scr=''{{schemeInfo.photo_url}}''> 這將是無效的,應該改為<img :src="schemeInfo.photo_url"> src前面的:時v-bind的簡寫,用於屬性繫結,當然,你也可以寫完整,如<div class="star-rating-read-only" v-bind:data-rating-score="schemeInfo.score_avg"></div>

  現在看似已經完成了,但是實際上我們的資料並沒有被渲染到模板上,這是因為vue 取值的方法{{ }}與django的模板語言衝突,vue取值並未生效,其實解決辦法至少有三個,可以參考這篇部落格:https://blog.csdn.net/jyfu2_12/article/details/79058819

  我還是喜歡第三種:

  將vue相關的html程式碼塊禁用django模板:

  在上述html程式碼前新增{% verbatim %},尾部新增{% endverbatim %},這樣vue就可以生效了,

 

  但是還有一個問題

       沒有被顯示出來,原因是類屬性為star-rating-read-only的div的js函式需要在資料完成之後載入才能生效

  正好,Vue.js 有一個方法 watch,它可以用來監測Vue例項上的資料變動。

  我們要監聽schemesInfo,如果資料變化,說明vue開始渲染,渲染完成DOM將發生變化,在vue中有個Vue.$nextTick(callback),當dom發生變化,更新後執行的回撥。

  在這個回撥函式中執行star-rating-read-only對應的js函式應該就可以解決這個問題,試一下修改common.js中的程式碼:

  

function loadGrade(){
    $('.star-rating-read-only').raty({
        readOnly: true,
        round: {down: .2, full: .6, up: .8},
        half: true,
        space: false,
        score: function () {
            return $(this).attr('data-rating-score');
        }
    });
}

function getHotScheme(){
    new Vue({
        el: '#scheme_app',
        data () {
            return {
            schemesInfo: null
            }
        },
        watch:{
            schemesInfo:function(){
                this.$nextTick(function(){
                    loadGrade()
                })
            }
        },
        mounted () {
            axios
            .get('/info/schemes')
            .then(response => (this.schemesInfo = response.data))
            .catch(function (error) { // 請求失敗處理
                console.log(error);
            });
        }
    })
}

 

  綠色部分是star-rating-read-only對應的js處理函式,紅色部分是我們對vue的修改完善,這樣修改以後,果不其然,資料都正確的渲染在了模板上

  

&n