内容 | 参考链接 |
---|---|
Vue3.0 项目启动 | Vue3.0 项目启动(打造企业级音乐App) |
Vue3.0项目——打造企业级音乐App(一) | Tab栏、轮播图、歌单列表、滚动组件 |
Vue3.0项目——打造企业级音乐App(二) | 图片懒加载、v-loading指令的开发和优化 |
vue3.0-music
该项目为移动端的项目,我们要设置缩放比例为 1,并且禁止用户双击缩放。
在 main.js 中引入样式文件
import '@/assets/scss/index.scss'
总体效果图:
header.vue 组件
<template>
<div class="header">
<span class="icon"></span>
<h1 class="text">Joyful Music</h1>
<router-link class="mine" to="/user">
<i class="icon-mine"></i>
</router-link>
</div>
</template>
<script>
export default {
name: 'm-header'
}
</script>
<style lang="scss" scoped>...</style>
tab 组件
<template>
<div class="tab">
<router-link
class="tab-item"
v-for="tab in tabs"
:key="tab.path"
:to="tab.path"
>
<span class="tab-link">
{{tab.name}}
</span>
</router-link>
</div>
</template>
<script>
export default {
name: 'tab',
data() {
return {
tabs: [
{
name: '推荐',
path: '/recommend'
},
{
name: '歌手',
path: '/singer'
},
{
name: '排行',
path: '/top-list'
},
{
name: '搜索',
path: '/search'
}
]
}
}
}
</script>
<style lang="scss" scoped>...</style>
App.vue 组件
<template>
<m-header></m-header>
<tab></tab>
<router-view></router-view>
</template>
<script>
import Header from '@/components/header/header.vue'
import Tab from '@/components/tab/tab.vue'
export default {
components: {
MHeader: Header,
Tab
}
}
</script>
<style lang="scss"></style>
./router/index.js 文件
import { createRouter, createWebHashHistory } from 'vue-router'
import Recommend from '@/views/recommend'
import Singer from '@/views/singer'
import TopList from '@/views/top-list'
import Search from '@/views/search'
const routes = [
{
path: '/',
redirect: '/recommend' // 重定向
},
{
path: '/recommend',
component: Recommend
},
{
path: '/singer',
component: Singer
},
{
path: '/top-list',
component: TopList
},
{
path: '/search',
component: Search
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router
./server/base.js 文件
import axios from 'axios'
const ERR_OK = 0
// 开发环境下这样定义baseURL
const baseURL = '/'
axios.defaults.baseURL = baseURL
export function get(url, params) {
return axios.get(url, {
params
}).then((res) => {
const serverData = res.data
if (serverData.code === ERR_OK) {
return serverData.result
}
}).catch((e) => {
console.log(e)
})
}
./server/recommend.js 文件
import { get } from './base'
export function getRecommend() {
return get('/api/getRecommend')
}
recommend.vue 组件
<template>
<div class="recommend">
推荐页面
</div>
</template>
<script>
import { getRecommend } from '@/service/recommend'
export default {
name: 'recommend',
async created() {
const result = await getRecommend()
console.log(result)
}
}
</script>
轮播图效果使用的是 BetterScroll 2.0 参考链接
./base/slider/use-slider.js 文件
new BScroll()
可以接收多个参数,第二个参数可以是对象的形式,里面添加多个参数import BScroll from '@better-scroll/core'
import Slide from '@better-scroll/slide'
import { onMounted, onUnmounted, ref } from 'vue'
BScroll.use(Slide)
export default function useSlider(wrapperRef) {
const slider = ref(null)
const currentPageIndex = ref(0)
onMounted(() => {
const sliderVal = slider.value = new BScroll(wrapperRef.value, {
click: true,
scrollX: true, // 横向滚动
scrollY: false,
momentum: false, // 避免惯性动画带来的快速滚动时的闪烁的问题和快速滑动时一次滚动多页的问题
bounce: false, // 避免在循环衔接的时候出现闪烁
probeType: 2, // 在用户拖动 slide 时,实时获取到 slide 的 PageIndex 的改变,需要设置为 2 or 3
slide: true
})
sliderVal.on('slideWillChange', (page) => {
currentPageIndex.value = page.pageX
})
})
// 销毁
onUnmounted(() => {
slider.value.destroy()
})
return {
slider,
currentPageIndex
}
}
./component/base/slider/slider.vue 组件
<template>
<div class="slider" ref="rootRef">
<div class="slider-group">
<div
class="slider-page"
v-for="item in sliders"
:key="item.id"
>
<a :href="item.link">
<img :src="item.pic"/>
</a>
</div>
</div>
<div class="dots-wrapper">
<span
class="dot"
v-for="(item, index) in sliders"
:key="item.id"
:class="{'active': currentPageIndex === index}">
</span>
</div>
</div>
</template>
<script>
import { ref } from 'vue'
import useSlider from './use-slider'
export default {
name: 'slider',
props: {
sliders: {
type: Array,
default() {
return []
}
}
},
setup() {
const rootRef = ref(null)
const { currentPageIndex } = useSlider(rootRef)
useSlider(rootRef)
return {
rootRef,
currentPageIndex
}
}
}
</script>
<style lang="scss" scoped>...</style>
./views/recommend.vue 组件
<template>
<div class="recommend">
<div class="slider-warpper">
<div class="slider-content">
<slider v-if="sliders.length" :sliders="sliders"></slider>
</div>
</div>
</div>
</template>
<script>
import { getRecommend } from '@/service/recommend'
import Slider from '@/components/base/slider/slider'
export default {
name: 'recommend',
components: {
Slider
},
data() {
return {
sliders: []
}
},
async created() {
const result = await getRecommend()
// 拿到数据
this.sliders = result.sliders
}
}
</script>
效果图如下:
./components/scroll/use-scroll.js 文件
observe-dom 插件特性:
import BScroll from '@better-scroll/core'
import ObserveDOM from '@better-scroll/observe-dom'
import { onMounted, onUnmounted, ref } from 'vue'
BScroll.use(ObserveDOM)
export default function useScroll(warpperRef, options) {
const scroll = ref(null)
onMounted(() => {
scroll.value = new BScroll(warpperRef.value, {
observeDOM: true,
...options
})
})
onUnmounted(() => {
scroll.value.destroy()
})
}
./component/scroll/scroll.vue 组件
<template>
<div ref="rootRef">
<slot></slot>
</div>
</template>
<script>
import useScroll from './use-scroll'
import { ref } from 'vue'
export default {
name: 'scroll',
// 组件的默认行为
props: {
click: {
type: Boolean,
default: true
}
},
setup(props) {
const rootRef = ref(null)
useScroll(rootRef, props)
return {
rootRef
}
}
}
</script>
./views/recommend.vue 组件
<template>
<div class="recommend">
<scroll class="recommend-content">
<div>
<div class="slider-wrapper">
<div class="slider-content">
<slider v-if="sliders.length" :sliders="sliders"></slider>
</div>
</div>
<div class="recommend-list">
<h1 class="list-title">热门歌单推荐</h1>
<ul>
<li
v-for="item in albums"
class="item"
:key="item.id"
>
<div class="icon">
<img width="60" height="60" :src="item.pic">
</div>
<div class="text">
<h2 class="name">
{{ item.username }}
</h2>
<p class="title">
{{item.title}}
</p>
</div>
</li>
</ul>
</div>
</div>
</scroll>
</div>
</template>
<script>
import { getRecommend } from '@/service/recommend'
import Slider from '@/components/base/slider/slider'
import Scroll from '@/components/base/scroll/scroll'
export default {
name: 'recommend',
components: {
Slider,
Scroll
},
data() {
return {
sliders: [],
albums: []
}
},
async created () {
const result = await getRecommend()
this.sliders = result.sliders
this.albums = result.albums
}
}
</script>
不积跬步无以至千里 不积小流无以成江海
点个关注不迷路,持续更新中…