有接口如下:
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 取值并未生效, 其实解决办法至少有三个, 可以参考这篇博客:
我还是喜欢第三种:
将 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 的修改完善, 这样修改以后, 果不其然, 数据都正确的渲染在了模板上
来源: https://www.cnblogs.com/wangbaojun/p/11145887.html