文章目录
练习一:点击更改颜色
作业需求:点击列表中的哪一项,那么该项文字变为红色(结合v-for和v-bind来实现)
实现效果:
实现代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>作业</title>
<style>
.active{
color: red;
}
</style>
</head>
<body>
<div id="app">
<ul>
<li @click="btnClick(index)" :class="{active:currentIndex === index}" v-for="(item,index) in movies">{{item}}</li>
</ul>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
movies:['哆啦A梦I','哆啦A梦II','哆啦A梦III','哆啦A梦IV'],
currentIndex:-1
},
methods:{
btnClick(index){
this.currentIndex = index
}
}
})
</script>
</body>
</html>
练习二:TarBar案例的实现
作业需求:
实现代码:
1、实现逻辑
-
npm init webpack tabbar
,创建项目,目录结构如下
-
在base.css中设置基础样式,即清除浏览器自带样式
-
TabBarItem.vue 设置插槽并设置样式并导出
<template> <div class="tab-bar-item"> <slot name="item-icon"></slot> <slot name="item-text"></slot> <!-- <img src="../../assets/img/tabbar/shouye.svg" alt=""> <div>首页</div>--> </div> </template> <script> export default { name: "TabBarItem" } </script> <style scoped> .tab-bar-item { flex: 1; text-align: center; height: 49px; font-size: 14px; } .tab-bar-item img{ width: 24px; height: 24px; margin-top: 3px; /*将图片的默认3px去掉*/ vertical-align: middle; } </style>
-
TabBar.vue 中设置插槽并导出
<template> <div id="tab-bar"> <!-- 设置插槽--> <slot></slot> </div> </template> <script> export default { name: "TabBar" } </script> <style scoped> #tab-bar { display: flex; background-color: #f6f6f6; position: fixed; left: 0; right: 0; bottom: 0; /*设置阴影:x方向,y方向,阴影宽度,阴影颜色*/ box-shadow: 0 -1px 1px rgba(100,100,100,.1); } </style>
-
App.vue 中导入、注册、使用组件
<template> <div id="app"> <!-- 3、使用组件--> <tab-bar> <tab-bar-item> <img slot="item-icon" src="./assets/img/tabbar/shouye.svg" alt=""> <div slot="item-text">首页</div> </tab-bar-item> <tab-bar-item> <img slot="item-icon" src="./assets/img/tabbar/profile.svg" alt=""> <div slot="item-text">分类</div> </tab-bar-item> <tab-bar-item> <img slot="item-icon" src="./assets/img/tabbar/gouwuche.svg" alt=""> <div slot="item-text">购物车</div> </tab-bar-item> <tab-bar-item> <img slot="item-icon" src="./assets/img/tabbar/wode.svg" alt=""> <div slot="item-text">我的</div> </tab-bar-item> </tab-bar> </div> </template> <script> /*1、导入组件*/ import TabBar from "./components/tabbar/TabBar"; import TabBarItem from "./components/tabbar/TabBarItem"; export default { name: 'App', components:{ /*2、注册组件*/ TabBar, TabBarItem } } </script> <style> /*导入基本样式*/ @import "./assets/css/base.css"; </style>
2、TarBar案例的实现思路
-
1、封装TarBar组件
- 自定义TarBar组件,在App中使用
- 让TarBar处于底部,并且设置相关的样式
-
2、TarBar中显示的内容由外界决定
- 定义插槽
- flex布局平分TarBar
-
3、自定义TabBarItem.vue,可以传入图片和文字
- 定义TarBarItem,并且定义两个插槽:图片、文字
- 给两个插槽外层包装 div,用于设置样式
- 填充插槽,实现底部TarBar的效果
<template> <!-- 所有的Item都展示同一个图片,同一个文字--> <div class="tab-bar-item" @click="itemClick"> <div v-if="!isActive"><slot name="item-icon"></slot> </div> <div v-else><slot name="item-icon-active"></slot> </div> <div :style="activeStyle"> <slot name="item-text"></slot> </div> </div> </template> <script> export default { name: "TabBarItem", props:{ path:String, activeColor:{ type:String, default:'red' } }, data(){ return { // isActive:true } }, /*搞一个计算属性*/ computed:{ isActive(){ /*拿到活跃路由的path与当前路径的path作为对比*/ /* * /home -> item1(/home) = true * /home -> item2(/category) = false * indexOf()方法:寻找,找到的话不为-1*/ return this.$route.path.indexOf(this.path) !== -1 }, activeStyle(){ return this.isActive ? {color:this.activeColor} :{} } }, methods:{ itemClick(){ this.$router.replace(this.path);// 该方法允许返回 } } } </script> <style scoped> .tab-bar-item { /*使盒子都有相同的长度*/ flex: 1; text-align: center; height: 49px; font-size: 14px; } .tab-bar-item img{ width: 24px; height: 24px; margin-top: 3px; /*将图片的默认3px去掉*/ vertical-align: middle; } /* !*设置 active 下的状态*! .active{ color: red; }*/ </style>
-
4、App.vue 使用组件
<template>
<div id="app">
<!-- 3、使用组件-->
<tab-bar>
<tab-bar-item path="/home" activeColor="deeppink">
<img slot="item-icon" src="./assets/img/tabbar/home.svg" alt="">
<img slot="item-icon-active" src="./assets/img/tabbar/home_active.svg" alt="">
<div slot="item-text">首页</div>
</tab-bar-item>
<tab-bar-item path="/category" activeColor="deeppink">
<img slot="item-icon" src="./assets/img/tabbar/category.svg" alt="">
<img slot="item-icon-active" src="./assets/img/tabbar/category_active.svg" alt="">
<div slot="item-text">分类</div>
</tab-bar-item>
<tab-bar-item path="/cart" activeColor="deeppink">
<img slot="item-icon" src="./assets/img/tabbar/cart.svg" alt="">
<img slot="item-icon-active" src="./assets/img/tabbar/cart_active.svg" alt="">
<div slot="item-text">购物车</div>
</tab-bar-item>
<tab-bar-item path="/profile" activeColor="deeppink">
<img slot="item-icon" src="./assets/img/tabbar/profile.svg" alt="">
<img slot="item-icon-active" src="./assets/img/tabbar/profile_active.svg" alt="">
<div slot="item-text">我的</div>
</tab-bar-item>
</tab-bar>
<router-view></router-view>
</div>
</template>
<script>
/*1、导入组件*/
import TabBar from "./components/tabbar/TabBar";
import TabBarItem from "./components/tabbar/TabBarItem";
export default {
name: 'App',
components:{
/*2、注册组件*/
TabBar,
TabBarItem
}
}
</script>
<style>
/*导入基本样式*/
@import "./assets/css/base.css";
</style>
- 4、index.js 中设置相关属性
3、给 TabBarItem 传入 active 图片
- 在 TabBarItem 组件中设置插槽用于存放图片以及文字,并设置active下的style属性为
color:red
- 在App.vue中设置两种状态下的的图片显示
文件路径的引用问题——取别名
情况二:HTML中的图片路径需要加~
练习三:返回顶部BackTop
1. 实现逻辑
.native
- 对组件的监听事件- 使用
@click.native="backClick"
,执行对原生组件的根元素的监听
- 在我们需要监听一个组件的原生事件时,必须给对应的事件加上
.native
修饰符,才能进行监听 - 例如:拿到组件.scroll内容.scrollTo方法()
2.代码实现
src/components/content/backTop/BackTop.vue
<template>
<div class="back-top">
<img src="~assets/img/common/top.png" alt="">
</div>
</template>
<script>
export default {
name: "BackTop"
}
</script>
<style scoped>
.back-top {
position: fixed;
right: 8px;
bottom: 55px;
}
.back-top img {
width: 43px;
height: 43px;
}
</style>
src/components/common/scroll/Scroll.vue
<template>
<div class="wrapper" ref="wrapper">
<div class="content">
<slot></slot>
</div>
</div>
</template>
<script>
import BScroll from 'better-scroll'
export default {
name: "Scroll",
props: {
probeType: {
type: Number,
default: 0
},
pullUpLoad: {
type: Boolean,
default: false
}
},
data() {
return {
scroll: null,
message: '哈哈哈'
}
},
mounted() {
// 1.创建BScroll对象
this.scroll = new BScroll(this.$refs.wrapper, {
click: true,
probeType: this.probeType,
pullUpLoad: this.pullUpLoad
})
// 2.监听滚动的位置
if (this.probeType === 2 || this.probeType === 3) {
this.scroll.on('scroll', (position) => {
// console.log(position);
this.$emit('scroll', position)
})
}
// 3.监听scroll滚动到底部
if (this.pullUpLoad) {
this.scroll.on('pullingUp', () => {
this.$emit('pullingUp')
})
}
},
methods: {
scrollTo(x, y, time=300) {
this.scroll && this.scroll.scrollTo(x, y, time)
},
refresh() {
this.scroll && this.scroll.refresh()
},
finishPullUp() {
this.scroll && this.scroll.finishPullUp()
},
getScrollY() {
return this.scroll ? this.scroll.y : 0
}
}
}
</script>
<style scoped>
</style>
src/views/home/Home.vue
<template>
<div id="home" class="wrapper">
<nav-bar class="home-nav"><div slot="center">购物街</div></nav-bar>
<tab-control :titles="['流行', '新款', '精选']"
@tabClick="tabClick"
ref="tabControl1"
class="tab-control" v-show="isTabFixed"/>
<scroll class="content"
ref="scroll"
:probe-type="3"
@scroll="contentScroll"
:pull-up-load="true"
@pullingUp="loadMore">
<home-swiper :banners="banners" @swiperImageLoad="swiperImageLoad"/>
<recommend-view :recommends="recommends"/>
<feature-view/>
<tab-control :titles="['流行', '新款', '精选']"
@tabClick="tabClick"
ref="tabControl2"/>
<good-list :goods="showGoods"/>
</scroll>
<back-top @click.native="backClick" v-show="isShowBackTop"/>
</div>
</template>
<script>
import HomeSwiper from './childComps/HomeSwiper'
import RecommendView from './childComps/RecommendView'
import FeatureView from './childComps/FeatureView'
import NavBar from 'components/common/navbar/NavBar'
import TabControl from 'components/content/tabControl/TabControl'
import GoodList from 'components/content/goods/GoodsList'
import Scroll from 'components/common/scroll/Scroll'
import BackTop from 'components/content/backTop/BackTop'
import { getHomeMultidata, getHomeGoods } from "network/home"
import {debounce} from "common/utils";
export default {
name: "Home",
components: {
HomeSwiper,
RecommendView,
FeatureView,
NavBar,
TabControl,
GoodList,
Scroll,
BackTop
},
data() {
return {
banners: [],
recommends: [],
goods: {
'pop': {page: 0, list: []},
'new': {page: 0, list: []},
'sell': {page: 0, list: []},
},
currentType: 'pop',
isShowBackTop: false,
tabOffsetTop: 0,
isTabFixed: false,
saveY: 0
}
},
computed: {
showGoods() {
return this.goods[this.currentType].list
}
},
destroyed() {
console.log('home destroyed');
},
activated() {
this.$refs.scroll.scrollTo(0, this.saveY, 0)
this.$refs.scroll.refresh()
},
deactivated() {
this.saveY = this.$refs.scroll.getScrollY()
},
created() {
// 1.请求多个数据
this.getHomeMultidata()
// 2.请求商品数据
this.getHomeGoods('pop')
this.getHomeGoods('new')
this.getHomeGoods('sell')
},
mounted() {
// 1.图片加载完成的事件监听
const refresh = debounce(this.$refs.scroll.refresh, 50)
this.$bus.$on('itemImageLoad', () => {
refresh()
})
},
methods: {
/**
* 事件监听相关的方法
*/
tabClick(index) {
switch (index) {
case 0:
this.currentType = 'pop'
break
case 1:
this.currentType = 'new'
break
case 2:
this.currentType = 'sell'
break
}
this.$refs.tabControl1.currentIndex = index;
this.$refs.tabControl2.currentIndex = index;
},
backClick() {
/*返回顶部*/
this.$refs.scroll.scrollTo(0, 0)
},
/*该方法是判断滑动的时候是否显示返回顶部的按钮*/
contentScroll(position) {
// 1.判断BackTop是否显示,加负号是为了让其转为正数
this.isShowBackTop = (-position.y) > 1000
// 2.决定tabControl是否吸顶(position: fixed)
this.isTabFixed = (-position.y) > this.tabOffsetTop
},
loadMore() {
this.getHomeGoods(this.currentType)
},
swiperImageLoad() {
this.tabOffsetTop = this.$refs.tabControl2.$el.offsetTop;
},
/**
* 网络请求相关的方法
*/
getHomeMultidata() {
getHomeMultidata().then(res => {
this.banners = res.data.banner.list;
this.recommends = res.data.recommend.list;
})
},
getHomeGoods(type) {
const page = this.goods[type].page + 1
getHomeGoods(type, page).then(res => {
this.goods[type].list.push(...res.data.list)
this.goods[type].page += 1
// 完成上拉加载更多
this.$refs.scroll.finishPullUp()
})
}
}
}
</script>
<!--scoped 表示局部作用域,代表此处的css只在当前文件中起效果
-->
<style scoped>
#home {
/*padding-top: 44px;*/
height: 100vh; /*vh 表示viewport height视口高度*/
position: relative;
}
.home-nav {
background-color: var(--color-tint);
color: #fff;
/*在使用浏览器原生滚动时, 为了让导航不跟随一起滚动*/
/*position: fixed;*/
/*left: 0;*/
/*right: 0;*/
/*top: 0;*/
/*z-index: 9;*/
}
.content {
overflow: hidden;
position: absolute;
top: 44px;
bottom: 49px;
left: 0;
right: 0;
}
.tab-control {
position: relative;
z-index: 9;
}
/*.content {*/
/*height: calc(100% - 93px);*/
/*overflow: hidden;*/
/*margin-top: 44px;*/
/*}*/
</style>
练习四:滑动中的上拉加载更多