[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ApjGDxQM-1655734119007)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4bcd5ea8327c4b2d855e1acb1f9d9975~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image?)]

浏览器地址栏输入 chrome://extensions/
右上角开发者模式 - 打开开关。
把 vue3_devtools.crx 拖放进去安装。(vue3_devtools.crx评论区的文件里包含有)
打开终端工具,输入 vue create 项目名称 创建 Vue3 + TS项目
vue create vue3-ts
温馨提醒:如果创建失败,需要提前安装 @vue/cli 脚手架工具,才能通过以上命令创建项目。 如何安装 @vue/cli 官方教程: cli.vuejs.org/zh/guide/in…
Vue3 + TypeScript 配置如下图: 
<template>
<h1>Bilibili 主页</h1>
<router-link to="/video/1">点我去视频详情页</router-link>
</template>
<template>
<h2>视频详情页</h2>
<router-link to="/">点我回首页</router-link>
</template>
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
const routes: Array<RouteRecordRaw> = [
{
path: '/',
component: () => import('@/views/Home/index.vue')
},
{
path: '/video/:id',
component: () => import('@/views/Video/index.vue')
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router
<template>
<router-view/>
</template>
这样就可以看见我们新建的首页页面了。
打开终端工具,输入 npm run serve 即可运行项目。
npm run serve
评论区里提供了项目 图片素材 和 样式文件,下载直接使用就可。
把素材文件夹中的 assets 文件夹移动到项目中,覆盖项目的 src\assets 文件夹。
项目入口文件 src\main.ts 里导入base.less、iconfont.less文件:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
//新导入文件:
import '@/assets/styles/base.less'
import '@/assets/styles/iconfont.less'
const app = createApp(App)
app.use(router)
app.mount('#app')

温馨提醒:新建三个文件备用即可,组件里面暂时不需要写入内容。

<template>
<!-- <h1>Bilibili 主页</h1> -->
<!-- <router-link to="/video/1">点我去视频详情页</router-link> -->
<!-- 新增头部组件 -->
<AppHeader />
</template>
<script setup lang="ts">
// script setup 只需要导入组件,无需注册
import AppHeader from '@/components/app-header.vue'
</script>
恭喜你已经学会在 Vue3 项目中如何导入组件和使用组件啦,为自己鼓掌。👏
此时的项目截图如下:

前端领域有很多成熟的组件库可以提高我们的开发效率,频道模块我们使用组件库快速实现。⚡
Vant 是 有赞前端团队 开源的移动端组件库,Vant 官方提供了 Vue3 版本,感谢有赞前端团队的贡献。🎉
打开终端工具,输入 npm i vant@next 即可安装,vant@next 表示安装最新版 Vant 3。
npm i vant@next
npm i babel-plugin-import -D
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins: [
[
'import',
{
libraryName: 'vant',
libraryDirectory: 'es',
style: true
}
]
]
}
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import '@/assets/styles/base.less'
import '@/assets/styles/iconfont.less'
// 导入Vant组件
import { Tab, Tabs } from 'vant'
const app = createApp(App)
// 注册Vant组件
app.use(Tab)
app.use(Tabs)
app.use(router)
app.mount('#app')
<template>
<van-tabs v-model:active="active">
<van-tab title="标签 1">内容 1</van-tab>
<van-tab title="标签 2">内容 2</van-tab>
<van-tab title="标签 3">内容 3</van-tab>
<van-tab title="标签 4">内容 4</van-tab>
</van-tabs>
</template>
<script setup lang="ts"> // ref 函数用于定义模板中使用的响应式数据,相当于 Vue2 的 data import { ref } from 'vue'
// active 表示当前选中标签的下标为 0
const active = ref(0) </script>
<template>
<!-- 头部组件 -->
<AppHeader />
<!-- 新增频道组件 -->
<HomeChannel />
</template>
<script setup lang="ts"> // script setup 只需要导入组件,无需注册\
import AppHeader from '@/components/app-header.vue'
//新增如下代码:
import HomeChannel from './components/home-channel.vue' </script>
这时,效果图如下: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2TTFQ8EB-1655734119009)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/755638e1678e4c97996a41e29d1809e0~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image?)]
恭喜你已经学会在 Vue3 项目中如何使用 Vant3 组件库的组件啦,为自己鼓掌。👏
npm i mockjs @types/mockjs -D
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import '@/assets/styles/base.less'
import '@/assets/styles/iconfont.less'
import { Tab, Tabs } from 'vant'
//添加mock导入
import '@/mock/index'
const app = createApp(App)
app.use(Tab)
app.use(Tabs)
app.use(router)
app.mount('#app')
npm i axios
<template>
<van-tabs v-model:active="active">
<van-tab title="标签 1">内容 1</van-tab>
<van-tab title="标签 2">内容 2</van-tab>
<van-tab title="标签 3">内容 3</van-tab>
<van-tab title="标签 4">内容 4</van-tab>
</van-tabs>
</template>
<script setup lang="ts"> import { ref } from 'vue'
//导入axios
import axios from 'axios'
const active = ref(0)
//使用axios发起网络请求
axios({
url: '/navList',
method: 'get'
}).then(res => {
console.log('获取频道数据', res.data) +
}) </script>
控制台输出如下:

恭喜你已经学会在 Vue3 项目中如何使用 Axios 发送请求获取数据啦,再为自己鼓掌。👏
修改 src\views\Home\components\home-channel.vue 文件
<template>
<van-tabs v-model:active="active">
<van-tab v-for="item in list" :key="item.id" :title="item.text"></van-tab>
<!-- <van-tab title="标签 1">内容 1</van-tab> -->
<!-- <van-tab title="标签 2">内容 2</van-tab> -->
<!-- <van-tab title="标签 3">内容 3</van-tab> -->
<!-- <van-tab title="标签 4">内容 4</van-tab> -->
</van-tabs>
</template>
<script setup lang="ts">
// ref 函数用于定义模板中使用的响应式数据,相当于 Vue2 的 data
import { ref } from 'vue'
import axios from 'axios'
// TypeScript 的接口用于标记数据格式
interface INavItem {
id: string
text: string
}
const active = ref(0)
// 频道数据, <INavItem[]> 表示 list 数据为数组,数组的每一项需要复合 INavItem 接口的格式
// TypeScript 好处:模板中使用 list 和 item 的时候,鼠标移入有类型提醒
const list = ref<INavItem[]>([])
axios({
url: '/navList',
method: 'get'
}).then(res => {
list.value = res.data.result
console.log('获取频道数据', res.data)
})
</script>
此时项目截图如下:
恭喜你已经学会在 Vue3 项目中如何使用 TypeScript 的接口定义数据格式了,再为自己鼓掌。👏
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import '@/assets/styles/base.less'
import '@/assets/styles/iconfont.less'
import '@/mock/index'
//新增Swipe, SwipeItem组件:
import { Tab, Tabs, Swipe, SwipeItem } from 'vant'
const app = createApp(App)
app.use(Tab)
app.use(Tabs)
//新增使用:
app.use(Swipe)
app.use(SwipeItem)
app.use(store)
app.use(router)
app.mount('#app')
<template>
<van-swipe class="my-swipe" :autoplay="3000" indicator-color="white">
<van-swipe-item v-for="item in list" :key="item.imgSrc">
<img :src="item.imgSrc" alt="图片加载失败" />
</van-swipe-item>
</van-swipe>
</template>
<script setup lang="ts"> // ref 函数用于定义模板中使用的响应式数据,相当于 Vue2 的 data
import { ref } from 'vue'
import axios from 'axios'
interface ISwiper{
link: string
imgSrc: string
}
const list = ref<ISwiper[]>([])
axios({
url: '/swiperList',
method: 'get'
}).then(res => {
list.value = res.data.result
console.log('轮播图数据', res.data)
}) </script>
<style lang="less" scoped> .my-swipe {
img {
width: 100%;
}
} </style>
<template>
<!-- 头部组件 -->
<AppHeader />
<!-- 频道组件 -->
<HomeChannel />
<!-- 新增轮播图组件 -->
<HomeSwipe />
</template>
<script setup lang="ts"> import AppHeader from '@/components/app-header.vue'
import HomeChannel from '@/views/Home/components/home-channel.vue'
//导入轮播图组件:
import HomeSwipe from '@/views/Home/components/home-swipe.vue' </script>
此时项目截图如下: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Z0ceCcF-1655734119009)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a01625a5879e414cb843e22b27e5b7a6~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image?)]
恭喜你已经学会在 Vue3 项目中如何使用 Vant3 + Axios + TypeScirpt组合使用啦 ,你的格局已经打开,为自己努力学习鼓掌三次。👏👏👏
可能有些小伙伴的轮播图看不到图片,主要是 B 站的图片做了防盗链处理(我们能理解)。
我们可以添加代码避免出现这种情况(我们能通过技术破解访问限制)😎
打开项目文件:public\index.html,添加以下代码即可修复问题。
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
//添加此如下代码:
<meta name="referrer" content="no-referrer">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
</head>
<template>
<div class="list">
<AppVideoItem v-for="item in list" :key="item.id" :video="item" />
</div>
</template>
<script setup lang="ts"> import { ref } from 'vue'
import axios from 'axios'
import AppVideoItem from '@/components/app-video-item.vue'
interface IVideoItem {
id: number;
imgSrc: string;
desc: string;
playCount: string;
commentCount: string;
videoSrc: string;
}
const list = ref<IVideoItem[]>([])
axios({
method: 'get',
url: '/videosList'
}).then(res => {
console.log('视频列表的数据', res.data.result)
list.value = res.data.result
}) </script>
<style lang="less"> .list {
display: flex;
flex-wrap: wrap;
padding: 0 1vw;
} </style>
<template>
<router-link class="v-card" :to="`/video/${video.id}`">
<div class="card">
<div class="card-img">
<img class="pic" :src="video.imgSrc" :alt="video.desc" />
</div>
<div class="count">
<span>
<i class="iconfont icon_shipin_bofangshu"></i>
{{ video.playCount }}
</span>
<span>
<i class="iconfont icon_shipin_danmushu"></i>
{{ video.commentCount }}
</span>
</div>
</div>
<p class="title">{{ video.desc }}</p>
</router-link>
</template>
<script setup lang="ts"> import { defineProps, PropType } from 'vue'
interface IVideoItem {
id: number;
imgSrc: string;
desc: string;
playCount: string;
commentCount: string;
videoSrc: string;
}
// 🔔 父传子需要通过 defineProps 接收
// 🔔 PropType 用于指定数据格式
defineProps({
video: {
// Object 对象为 IVideoItem 接口格式
type: Object as PropType<IVideoItem>,
required: true
}
}) </script>
<style lang="less" scoped> .v-card {
width: 50%;
padding: 2vw 1vw;
.card {
position: relative;
background: #f3f3f3 url(~@/assets/images/default.png) center no-repeat;
background-size: 36%;
border-radius: 0.53333vw;
overflow: hidden;
.card-img {
.pic {
height: 100px;
width: 100%;
object-fit: cover;
}
}
.count {
background-image: linear-gradient(0deg, #000000d9, #0000);
color: #fff;
position: absolute;
bottom: 0;
left: 0;
right: 0;
font-size: 3vw;
display: flex;
align-items: center;
justify-content: space-between;
padding: 1.2vw 1.5vw;
span {
.iconfont {
font-size: 3vw;
}
}
}
}
.title {
margin-top: 1.5vw;
font-size: 3.2vw;
color: #212121;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
} </style>
<template>
<!-- 头部组件 -->
<AppHeader />
<!-- 频道组件 -->
<HomeChannel />
<!-- 轮播图组件 -->
<HomeSwipe />
<!-- 新增视频列表组件 -->
<HomeVideoList />
</template>
<script setup lang="ts"> import AppHeader from '@/components/app-header.vue'
import HomeChannel from '@/views/Home/components/home-channel.vue'
import HomeSwipe from '@/views/Home/components/home-swipe.vue'
//导入视频列表组件
import HomeVideoList from '@/views/Home/components/home-video-list.vue' </script>
好了项目到此就结束了,文件的如下,有需要的小伙伴可以自己领取哦。 链接: pan.baidu.com/s/1VL0a4Zva… 提取码: wu3o