python web(bottle框架)知行合一之-简单知识付费平台-”全栈“实践(16)---课程列表组件
PS:笔记只是为了更好表达我怎么语言表述,有些时候可能难免废话一推!
因知识有限, 如有错误, 欢迎指正!
每日细语:学海无涯苦作舟!
最终效果图:

续言
上一节,我们已经把底部的导航栏放置在了默认的页面渲染可见的第一个组件Index.vue组件,而它的上面还可以包含有其他组件,也可以是通过路由来进行匹配的。
这个就涉及到Index.vue组件里的子组件的渲染,也就是二级路由!
回顾我们的Index.vue组件代码:
<template>
<div>
<keep-alive>
<router-view></router-view>
</keep-alive>
<tabbar style="position:fixed">
<tabbar-item v-for="(item,index) in tabbars" @on-item-click="item_click" :key="index"
:link="{name:item.route_name,replace:true}" :selected="route_name===item.route_name?true:false">
<span slot="icon" class="iconfont tabbar-icon" :class="item.icon"></span>
<!--<span slot="icon-active" class="iconfont tabbar-icon" :class="item.icon_active"></span>-->
<span slot="label">{{item.name}}</span>
</tabbar-item>
</tabbar>
</div>
</template>
<script>
import {Tabbar, TabbarItem} from 'vux'
export default {
components: {
Tabbar,
TabbarItem
},
data () {
return {
route_name: '',
selected: 1,
tabbars: [
{
name: '课程',
route_name: 'home',
icon: 'icon-home',
icon_active: 'icon-homefill'
},
{
name: '我的',
route_name: 'member',
icon: 'icon-my',
icon_active: 'icon-myfill'
}
]
}
},
mounted () {
this.route_name = this.$route.name
},
methods: {
item_click (index) {
let item = this.tabbars[index]
if (item.route_name === this.route_name) {
document.body.scrollTop = 0
document.documentElement.scrollTop = 0
}
}
}
}
</script>
<style lang="less">
.tabbar-icon {
font-size: 23px;
line-height: 27px;
}
</style>
其中的代码:
<keep-alive>
<router-view></router-view>
</keep-alive>
说明了我们还可以在Index.vue渲染其他子组件。也就是我们的
- 课程列表组件
- 我的列表组件
所以我们的需要先配置好上述两个子组件的路由(即对应的组件)
重新规划结构:

修改route下的index.js
// 第一个界面所包含的相关组件
const Index = resolve => require(['../pages/Index/Index'], resolve)
const Course = resolve => require(['../pages/Index/Course/course'], resolve)
const Me = resolve => require(['../pages/Index/Me/me'], resolve)
const routes = [{
path: '/',
name: 'index',
component: Index,
children: [
{
path: '/r/course',
name: 'course',
component: Course,
meta: {
title: 'course',
keepAlive: true
}
},
{
path: '/r/me',
name: 'me',
component: Me,
meta: {
title: 'me',
keepAlive: true
}
}
]
}
]
export default routes

修改Index.vue文件:


遇到的问题是:子组件无法渲染出来?
尝试解决:

问题表现,必须包含在 <view-box ref="viewBox">的元素才会可见!!
有点奇怪!为什么呢?

发现问题点在外面的App.vue中的 <div class="base-bg"></div>:
<template>
<div id="app">
<div class="base-bg"></div>
<navigation>
<router-view></router-view>
</navigation>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style lang="less">
@import "~vux/src/styles/reset.less";
@import "~vux/src/styles/1px.less";
@import "./styles/common.less";
* {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
body {
background-color: @page-bg;
}
.base-bg {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: @page-bg;
z-index: -1;
}
.load-more-view {
height: 50px;
}
</style>
PS: z-index: -1; 这个设置为-1的时候显示就正常了!!
但是默认设置为了0 所以无法显示!!!

既然我们需要显示出课程列表的话,那么我们就需要在

包含对应的课程列表的中Item组件,用户显示我们的课程列表信息。
定义课程组件
course.vue代码:
<template>
<div>
<view-box ref="viewBox">
<h2>课程详细列表页面</h2>
<div class="list-body">
<template v-for="(item,index) in testData">
<course_item :item="item" :key="index"/>
</template>
</div>
</view-box>
</div>
</template>
<script>
import {
Swiper,
Rater,
ViewBox,
LoadMore,
InlineLoading,
Flexbox,
Badge
} from 'vux'
import course_item from './course_item.vue'
export default {
name: 'HelloWorld',
components: {
Flexbox,
Swiper,
Rater,
ViewBox,
LoadMore,
InlineLoading,
Badge,
course_item
},
data () {
return {
msg: 'Welcome to Your Vue.js App',
show1: true,
show2: false,
text1: '努力的加载中',
testData:[
{
'course_classify_code': '001',
'course_code_id': '1000',
'name': '爱因斯坦',
'title': '爱因斯坦的伟大',
'describe_simple': 0,
'describe_detailed': '不想详细的描述太多!!',
'img_cover': 'http:\/\/ss.gxtcwl.com\/images\/fe3ebd121b239eeca2899f8d0925d963.jpg?imageView2\/1\/w\/200\/h\/200\/q\/100',
'state': 2,
'all_num_count': 20,
'is_down': 1,
'is_sell': 1,
'is_flee': 0,
'price': 50,
'has_learn_num': 200,
'has_updata_num_count': 20,
'is_vip_flee': 1,
'author': '爱因斯坦',
'type': 3
},
{
'course_classify_code': '002',
'course_code_id': '1001',
'name': '爱因斯坦2',
'title': '爱因斯坦的伟大2',
'describe_simple':0,
'describe_detailed': '不想详细的描述太多!!3',
'img_cover': 'http:\/\/ss.gxtcwl.com\/images\/fe3ebd121b239eeca2899f8d0925d963.jpg?imageView2\/1\/w\/200\/h\/200\/q\/100',
'state': 2,
'all_num_count': 20,
'is_down': 1,
'is_sell': 1,
'is_flee': 1,
'price': 50,
'has_learn_num': 200,
'has_updata_num_count': 20,
'is_vip_flee': 0,
'author': '爱因斯坦',
'type': 3
},
{
'course_classify_code': '003',
'course_code_id': '1002',
'name': '爱因斯坦3',
'title': '爱因斯坦的伟大3',
'describe_simple':0,
'describe_detailed': '不想详细的描述太多!!3',
'img_cover': 'http:\/\/ss.gxtcwl.com\/images\/fe3ebd121b239eeca2899f8d0925d963.jpg?imageView2\/1\/w\/200\/h\/200\/q\/100',
'state': 2,
'all_num_count': 20,
'is_down': 1,
'is_sell': 1,
'is_flee': 1,
'price': 50,
'has_learn_num': 200,
'has_updata_num_count': 20,
'is_vip_flee': 0,
'author': '爱因斯坦',
'type': 3
},
{
'course_classify_code': '004',
'course_code_id': '1005',
'name': '爱因斯坦5',
'title': '爱因斯坦的伟大5',
'describe_simple': 0,
'describe_detailed': '不想详细的描述太多!!3',
'img_cover': 'http:\/\/ss.gxtcwl.com\/images\/fe3ebd121b239eeca2899f8d0925d963.jpg?imageView2\/1\/w\/200\/h\/200\/q\/100',
'state': 2,
'all_num_count': 20,
'is_down': 1,
'is_sell': 1,
'is_flee': 1,
'price': 50,
'has_learn_num': 200,
'has_updata_num_count': 20,
'is_vip_flee': 0,
'author': '爱因斯坦',
'type': 3
},
{
'course_classify_code': '006',
'course_code_id': '1006',
'name': '爱因斯坦6',
'title': '爱因斯坦的伟大6',
'describe_simple': 0,
'describe_detailed': '不想详细的描述太多!!3',
'img_cover': 'http:\/\/ss.gxtcwl.com\/images\/fe3ebd121b239eeca2899f8d0925d963.jpg?imageView2\/1\/w\/200\/h\/200\/q\/100',
'state': 2,
'all_num_count': 20,
'is_down': 1,
'is_sell': 1,
'is_flee': 1,
'price': 50,
'has_learn_num': 200,
'has_updata_num_count': 20,
'is_vip_flee': 0,
'author': '爱因斯坦',
'type': 3
},
{
'course_classify_code': '007',
'course_code_id': '1007',
'name': '爱因斯坦7',
'title': '爱因斯坦的伟大7',
'describe_simple': 0,
'describe_detailed': '不想详细的描述太多!!3',
'img_cover': 'http:\/\/ss.gxtcwl.com\/images\/fe3ebd121b239eeca2899f8d0925d963.jpg?imageView2\/1\/w\/200\/h\/200\/q\/100',
'state': 2,
'all_num_count': 20,
'is_down': 1,
'is_sell': 1,
'is_flee': 1,
'price': 50,
'has_learn_num': 200,
'has_updata_num_count': 20,
'is_vip_flee': 0,
'author': '爱因斯坦',
'type': 3
},
{
'course_classify_code': '008',
'course_code_id': '1008',
'name': '爱因斯坦8',
'title': '爱因斯坦的伟大8',
'describe_simple': 0,
'describe_detailed': '不想详细的描述太多!!3',
'img_cover': 'http:\/\/ss.gxtcwl.com\/images\/fe3ebd121b239eeca2899f8d0925d963.jpg?imageView2\/1\/w\/200\/h\/200\/q\/100',
'state': 2,
'all_num_count': 20,
'is_down': 1,
'is_sell': 1,
'is_flee': 1,
'price': 50,
'has_learn_num': 200,
'has_updata_num_count': 20,
'is_vip_flee': 0,
'author': '爱因斯坦',
'type': 3
},
{
'course_classify_code': '009',
'course_code_id': '1009',
'name': '爱因斯坦9',
'title': '爱因斯坦的伟大9',
'describe_simple': 0,
'describe_detailed': '不想详细的描述太多!!3',
'img_cover': 'http:\/\/ss.gxtcwl.com\/images\/fe3ebd121b239eeca2899f8d0925d963.jpg?imageView2\/1\/w\/200\/h\/200\/q\/100',
'state': 2,
'all_num_count': 20,
'is_down': 1,
'is_sell': 1,
'is_flee': 1,
'price': 50,
'has_learn_num': 200,
'has_updata_num_count': 20,
'is_vip_flee': 0,
'author': '爱因斯坦',
'type': 3
},
{
'course_classify_code': '0010',
'course_code_id': '10010',
'name': '爱因斯坦10',
'title': '爱因斯坦的伟大10',
'describe_simple': 0,
'describe_detailed': '不想详细的描述太多!!3',
'img_cover': 'http:\/\/ss.gxtcwl.com\/images\/fe3ebd121b239eeca2899f8d0925d963.jpg?imageView2\/1\/w\/200\/h\/200\/q\/100',
'state': 2,
'all_num_count': 20,
'is_down': 1,
'is_sell': 1,
'is_flee': 1,
'price': 50,
'has_learn_num': 200,
'has_updata_num_count': 20,
'is_vip_flee': 0,
'author': '爱因斯坦',
'type': 3
},
{
'course_classify_code': '0011',
'course_code_id': '10011',
'name': '爱因斯坦11',
'title': '爱因斯坦的伟大11',
'describe_simple':0,
'describe_detailed': '不想详细的描述太多!!3',
'img_cover': 'http:\/\/ss.gxtcwl.com\/images\/fe3ebd121b239eeca2899f8d0925d963.jpg?imageView2\/1\/w\/200\/h\/200\/q\/100',
'state': 2,
'all_num_count': 20,
'is_down': 1,
'is_sell': 1,
'is_flee': 1,
'price': 50,
'has_learn_num': 200,
'has_updata_num_count': 20,
'is_vip_flee': 0,
'author': '爱因斯坦',
'type': 3
},
{
'course_classify_code': '0012',
'course_code_id': '10012',
'name': '爱因斯坦12',
'title': '爱因斯坦的伟大12',
'describe_simple': 0,
'describe_detailed': '不想详细的描述太多!!3',
'img_cover': 'http:\/\/ss.gxtcwl.com\/images\/fe3ebd121b239eeca2899f8d0925d963.jpg?imageView2\/1\/w\/200\/h\/200\/q\/100',
'state': 2,
'all_num_count': 20,
'is_down': 1,
'is_sell': 1,
'is_flee': 1,
'price': 50,
'has_learn_num': 200,
'has_updata_num_count': 20,
'is_vip_flee': 0,
'author': '爱因斯坦',
'type': 3
},
{
'course_classify_code': '0013',
'course_code_id': '10013',
'name': '爱因斯坦13',
'title': '爱因斯坦的伟大13',
'describe_simple': 0,
'describe_detailed': '不想详细的描述太多!!3',
'img_cover': 'http:\/\/ss.gxtcwl.com\/images\/fe3ebd121b239eeca2899f8d0925d963.jpg?imageView2\/1\/w\/200\/h\/200\/q\/100',
'state': 2,
'all_num_count': 20,
'is_down': 1,
'is_sell': 1,
'is_flee': 1,
'price': 50,
'has_learn_num': 200,
'has_updata_num_count': 20,
'is_vip_flee': 0,
'author': '爱因斯坦',
'type': 3
},
{
'course_classify_code': '0014',
'course_code_id': '10014',
'name': '爱因斯坦14',
'title': '爱因斯坦的伟大14',
'describe_simple': 0,
'describe_detailed': '不想详细的描述太多!!3',
'img_cover': 'http:\/\/ss.gxtcwl.com\/images\/fe3ebd121b239eeca2899f8d0925d963.jpg?imageView2\/1\/w\/200\/h\/200\/q\/100',
'state': 2,
'all_num_count': 20,
'is_down': 1,
'is_sell': 1,
'is_flee': 1,
'price': 50,
'has_learn_num': 200,
'has_updata_num_count': 20,
'is_vip_flee': 0,
'author': '爱因斯坦',
'type': 3
},
{
'course_classify_code': '0015',
'course_code_id': '10015',
'name': '爱因斯坦15',
'title': '爱因斯坦的伟大15',
'describe_simple': 0,
'describe_detailed': '不想详细的描述太多!!3',
'img_cover': 'http:\/\/ss.gxtcwl.com\/images\/fe3ebd121b239eeca2899f8d0925d963.jpg?imageView2\/1\/w\/200\/h\/200\/q\/100',
'state': 2,
'all_num_count': 20,
'is_down': 1,
'is_sell': 1,
'is_flee': 1,
'price': 50,
'has_learn_num': 200,
'has_updata_num_count': 20,
'is_vip_flee': 0,
'author': '爱因斯坦',
'type': 3
},
{
'course_classify_code': '0016',
'course_code_id': '10016',
'name': '爱因斯坦16',
'title': '爱因斯坦的伟大16',
'describe_simple': 0,
'describe_detailed': '不想详细的描述太多!!3',
'img_cover': 'http:\/\/ss.gxtcwl.com\/images\/fe3ebd121b239eeca2899f8d0925d963.jpg?imageView2\/1\/w\/200\/h\/200\/q\/100',
'state': 2,
'all_num_count': 20,
'is_down': 1,
'is_sell': 1,
'is_flee': 1,
'price': 50,
'has_learn_num': 200,
'has_updata_num_count': 20,
'is_vip_flee': 0,
'author': '爱因斯坦',
'type': 3
},
{
'course_classify_code': '0017',
'course_code_id': '10017',
'name': '爱因斯坦17',
'title': '爱因斯坦的伟大17',
'describe_simple': 0,
'describe_detailed': '不想详细的描述太多!!3',
'img_cover': 'http:\/\/ss.gxtcwl.com\/images\/fe3ebd121b239eeca2899f8d0925d963.jpg?imageView2\/1\/w\/200\/h\/200\/q\/100',
'state': 2,
'all_num_count': 20,
'is_down': 1,
'is_sell': 1,
'is_flee': 1,
'price': 50,
'has_learn_num': 200,
'has_updata_num_count': 20,
'is_vip_flee': 0,
'author': '爱因斯坦',
'type': 3
}
]
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
course_item.vue 代码:
<template>
<div>
<h2>课程详细列表Item</h2>
</div>
</template>
<script>
export default {}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
最终效果显示:

显示对应的测试数据的列表的所有数据:
在course_item.vue 定义
props: {
item: {}
}
接受父组件传输的

完整代码:
<template>
<div>
<h2>{{item.title}}</h2>
</div>
</template>
<script>
export default {
props: {
item: {}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
修改之后显示的效果:

美化我们的course_item.vue样式组件
<template>
<div class="home-item">
<div class="left">
<img class="cover" :src="item.img_cover" alt="">
<badge v-if="item.is_vip_flee==1" text="VIP免费"></badge>
</div>
<div class="right">
<div class="r-t">
<div class="title line-1">{{item.title}}</div>
<!--<div class="abstract line-2">{{item.abstract}}</div>-->
</div>
<div class="r-d">
<template v-if="item.price > 0">
<span class="price">{{item.price}}</span>
</template>
<template v-else>
<span class="free">限时免费</span>
</template>
<span class="yd" v-if="item.has_learn_num">{{item.has_learn_num}}人在学</span>
</div>
</div>
</div>
</template>
<script>
import {Rater, Badge} from 'vux'
// lodash 通过降低 array、number、objects、string 等等的使用难度从而让 JavaScript 变得更简单。
// Lodash 的模块化方法 非常适用于:
// 遍历 array、object 和 string
// 对值进行操作和检测
// 创建符合功能的函数
var lodash = require('lodash')
export default {
components: {
Rater,
Badge
},
props: {
item: {}
},
filters: {
ceil: function (value) {
return lodash.ceil(value, 1)
}
}
}
</script>
<style lang="less">
.home-item {
display: flex;
flex-direction: row;
margin: 0.106667rem 0.213333rem;
background: #ffffff;
padding: 0.213333rem;
border-radius: 4px;
box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.1);
.left {
order: 2;
line-height: 1;
position: relative;
width: 3.333333rem;
height: 2.4rem;
.cover {
width: 3.333333rem;
height: 2.4rem;
background: #f9f9f9;
border-radius: 0.08rem;
line-height: 0;
}
.vux-badge {
border-radius: 0 0 0.08rem 0;
position: absolute;
bottom: 0;
right: 0;
background: #19be6b;
}
}
.right {
order: 1;
margin-right: 0.213333rem;
display: flex;
flex-grow: 1;
flex-direction: column;
justify-content: space-between;
.title {
font-size: 0.426667rem;
font-weight: bold;
color: #2e2e2e;
}
.abstract {
font-size: 12px;
color: #999999;
}
.r-t {
flex-grow: 1;
}
.r-d {
display: flex;
flex-direction: row;
align-items: flex-end;
justify-content: space-between;
span {
color: @Danger;
font-weight: 500;
font-size: 0.48rem;
line-height: 0.48rem;
}
.price::before {
content: "¥";
font-size: 10px;
}
.free {
color: #19be6b;
font-size: 0.426667rem;
}
.yd {
font-size: 12px;
font-size: 10px;
color: #999999;
}
}
}
}
</style>
效果:

感觉不对劲啊!
什么对应的比例压缩的不成人样了!!!
后来发现是需要使用flexible 来进行对应的自适应处理!
所以需要在main.js导入

最终结果:

完善一些对应的字段输出处理!

结束
以上笔记纯属个人学习实践总结,有兴趣的同学可以加群一起学习讨论QQ:308711822