一、uni-app是什么?
uni-app 是Dcloud 公司开发的一跨平台框架,基于Vue.js 开发一套代码可以打包到多个平台运行,比如小程序,支持多种小程序,比如微信小程序,支付宝小程序,百度小程序,抖音小程序等小程序。他还可以打包成原生app
二、uni-app 开发环境
uni-app 官方推荐使用HBuilderX开发工具,HBuilderX对uni-app 的开发提示非常友好,有非常丰富工具和插件市场。 下载地址www.dcloud.io/hbuilderx.h...
下载之后是一个压缩包,直接解压即可,然后点击HBuilderX.exe 进行打开。
三、新建项目和项目结构介绍
1. 新建项目
左上角点击文件 -> 新建 -> 项目。这时会弹出一个框来。

分别填写项目名称,项目存放的路径,选择项目模板,这里就默认选择第一个了,第一个最简单的模板,比较适合学习。Vue 版本就选择Vue3
2.目录结构介绍
js
douban/
├── pages/ 页面代码存放的位置
├── static/ 存放静态资源,如图片字体文件
├── unpackage/ 打包后的代码存放的位置
├── App.vue 根组件
├── index.html
├── main.js 入口文件
├── manifest.json 应用基本信息配置,平台差异化配置
├── pages.json 配置页面路由和一些全局配置
├── uni.promisfly.adaptor.js 主要用于解决 UniApp 中异步 API 的 Promise 化问题
└── uni.scss 全局的样式文件
uni-ui插件导入,在后面的豆瓣电影中我们会用到uni-ui中的评分组件。所以这里需要先安装。
选择顶部的 工具 -> 插件安装,这个时候会弹出来一个弹框
可以看到有已安装插件和安装新插件选项。选择安装新插件选项,然后点击底部的前往市场安装。
这时候会跳转到插件市场https://ext.dcloud.net.cn/?cat1=1&cat2=11 在导航栏 选择前端组件后,然后再进行搜索uni-ui,
选择第一个点进去,可以看到右侧有一个 下载插件并导入HBuilderX的按钮,点击进行安装,如果没有登录的话会弹出提示的弹框,去登录就好。如果没有账号注册一个再登录。登录之后再点击安装会弹出这样一个框
点击打开会弹出这样一个框让你选择要导入的项目,选择douban,点击确定,这个时候插件就开始安装中了

安装完成之后会再控制台安装成功的提示:

观察项目目录,会发现多了一个uni_modules目录,安装的插件都会在这里面,和我们平时开发Vue 项目时的node_modules差不多。这个时候就可以在项目里面正常使用uni-ui了。

四、豆瓣项目代码编写
先来分析下豆瓣的移动端结构m.douban.com/movie/
可以看到这个页面由5大模块组成,所以我们将它分为5个组件来开发,这里不会开发顶部和打开app 功能,因为这篇文章主要是介绍ui-niapp 开发。 所以我们在pages/index下面新建components 用来存放5个组件。再在pages/index下新建data 目录,用来存放数据。现在pages/index 如下:

TopDianying.vue
js
<template>
<view class="top-wrap">
<view class="title-wrap">
<view class="title-box">
<view class="title" :class="{ active: currIdx === 0 }" @click="setTopActive(0)">影院热映</view>
<view class="title" :class="{ active: currIdx === 1 }" @click="setTopActive(1)">豆瓣热门</view>
</view>
<view class="more">用App 看更多</view>
</view>
<view class="con-wrap">
<scroll-view :scroll-x="true">
<view class="list" :style="{ width: `calc(220rpx * ${topListRef.length})`}">
<view class="card" v-for="item in topListRef" :key="item.id">
<view class="img-wrap">
<view class="like"></view>
<image :src="item.image"></image>
</view>
<view class="bottom-info">
<text class="item-title">{{ item.title }}</text>
<uni-rate v-model="item.rate" :size="10" @change="onChange"/>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { topList, topList2 } from '../data/data'
const currIdx = ref(0)
const setTopActive = (index) => {
currIdx.value = index
const config = {
0: topList,
1: topList2
}
topListRef.value = config[index]
}
const topListRef = ref(topList)
const value = ref(2)
const onChange = (e) => {
console.log(e)
}
</script>
<style scoped lang="scss">
.top-wrap {
margin-top: 40rpx;
}
.title-wrap {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 40rpx;
padding: 0 40rpx;
.title-box{
display: flex;
}
.title {
font-size: 42rpx;
color: #818181;
&:first-child{
border-right: 2rpx solid #b2b2b2;
display: inline-block;
padding-right: 20rpx;
}
&:nth-child(2){
margin-left: 20rpx;
}
&.active {
color: #191919;
}
}
.more {
font-size: 26rpx;
color: #818181;;
}
}
.list {
display: flex;
}
.con-wrap {
.card{
width: 200rpx;
margin-right: 20rpx;
display: flex;
flex-direction: column;
align-items: center;
&:first-child {
margin-left: 40rpx;
}
.img-wrap {
border-radius: 12rpx;
overflow: hidden;
width: 100%;
image {
width: 100%;
height: 280rpx;
}
.like {
background-image: url('/static/xin.svg');
background-color: rgba(0, 0, 0, 0.3);
background-position: center center;
background-repeat: no-repeat;
background-size: 40rpx;
border-radius: 12rpx 0px;
}
}
.bottom-info {
display: flex;
flex-direction: column;
align-items: center;
}
.item-title {
font-weight: 700;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: center;
width: 220rpx;
}
}
}
</style>
在这个文件中我们可以看到:
- 用到了uni-app 内置的基础组件
view
,view
相当于我们平时网页开发的div,就是一个容器 - 还用到了
scroll-view
组件,scroll-view
也是uni-app 内置的基础组件,不过它可以配置滚动,配置横向滚动就添加:scroll-x="true"
, 配置纵向滚动就配置:scroll-y="true"
- 还用到了
image
基础组件, 它相当于我们网页开发中的img
用来渲染图片的 - 还用到了
text
组件,相当于网页中的span
或者p
标签,用来显示文本的组件 - 用到了一个扩展组件
uni-rate
, 扩展组件是必须要安装的,uni-rate
就来自我们之前安装的uni-ui LangCate.vue - 其他的就和平常我们开发vue项目 开发差不多,就不过多介绍了
js
<template>
<view class="lang-wrap">
<div class="card">
<view class="title-wrap">
<text class="title">国内即将上映</text>
<text class="more"></text>
</view>
<view class="info">
<text class="desc">近期将由5不新剧即将上映</text>
<image src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2907242293.jpg"></image>
</view>
</div>
<div class="card">
<view class="title-wrap">
<text class="title">全球值得期待</text>
<text class="more"></text>
</view>
<view class="info">
<text class="desc">近期将由5不新剧即将上映</text>
<image src="https://img2.doubanio.com/view/photo/s_ratio_poster/public/p2920171671.jpg"></image>
</view>
</div>
</view>
</template>
<script>
</script>
<style lang="scss" scoped>
.lang-wrap {
display: flex;
justify-content: space-between;
padding: 100rpx 40rpx;
.card {
box-shadow: 0 10px 20px 0 rgba(0,0,0,.05);
border: 1px solid #dfdfdf;
padding: 30rpx;
box-sizing: border-box;
width: calc(50% - 10rpx);
border-radius: 18rpx;
.title-wrap {
display: flex;
justify-content: space-between;
.title {
font-size: 34rpx
}
}
.info {
display: flex;
margin-top: 10rpx;
.desc {
flex: 1;
margin-right: 20rpx;
font-size: 26rpx;
line-height: 36rpx;
color: #818181;
}
image {
width: 114rpx;
height: 108rpx;
border-radius: 12rpx;
}
}
}
}
</style>
HotDianying.vue
js
<template>
<view>
<scroll-view scroll-x="auto">
<view class="card-list" :style="{ width: 610 * 3 + 'rpx'}">
<view class="card">
<view class="card-num">
共10部·用App打开
</view>
<view class="card-title">
<view class="hot-icon"></view>
<text class="card-text">实时热门电影</text>
</view>
<view class="list">
<view class="item" v-for="(item, index) in hotList" :key="item.id">
<view class="rank">{{ index + 1 }}</view>
<image :src="item.image"></image>
<view class="info">
<view class="title">{{ item.title }}</view>
<uni-rate v-model="item.rate" :size="12"></uni-rate>
</view>
</view>
</view>
</view>
<view class="card week-movie">
<view class="card-num">
共10部·用App打开
</view>
<view class="card-title">
<view class="hot-icon"></view>
<text class="card-text">一周口碑电影榜</text>
</view>
<view class="list">
<view class="item" v-for="(item, index) in weekMoviesRef" :key="item.id">
<view class="rank">{{ index + 1 }}</view>
<image :src="item.image"></image>
<view class="info">
<view class="title">{{ item.title }}</view>
<uni-rate v-model="item.rate" :size="12"></uni-rate>
</view>
</view>
</view>
</view>
<view class="card douban-top">
<view class="card-num">
共250部·用App打开
</view>
<view class="card-title">
<view class="hot-icon"></view>
<text class="card-text">豆瓣电影 Top250</text>
</view>
<view class="list">
<view class="item" v-for="(item, index) in doubanTopsRef" :key="item.id">
<view class="rank">{{ index + 1 }}</view>
<image :src="item.image"></image>
<view class="info">
<view class="title">{{ item.title }}</view>
<uni-rate v-model="item.rate" :size="12"></uni-rate>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { hotList, weekMovies, doubanTops } from '@/pages/index/data/data.js'
const hotListRef = ref(hotList)
const weekMoviesRef = ref(weekMovies)
const doubanTopsRef = ref(doubanTops)
</script>
<style lang="scss" scoped>
.card-list{
display: flex;
.card {
width: 580rpx;
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHdpZHRoPSIyOTAiIGhlaWdodD0iMjUwIj48ZGVmcz48bGluZWFyR3JhZGllbnQgeDE9IjEiIHkxPSIwIiB4Mj0iLjUiIHkyPSIxIiBpZD0iYSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzBGNzJBNyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzBGNzJBNyIgc3RvcC1vcGFjaXR5PSIwIi8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgeDE9Ii41IiB5MT0iMCIgeDI9Ii41IiB5Mj0iLjUiIGlkPSJjIj48c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjMDAyRDY0Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjMDAyRDY0IiBzdG9wLW9wYWNpdHk9IjAiLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCB4MT0iLjUiIHkxPSIwIiB4Mj0iLjUiIHkyPSIuNSIgaWQ9ImQiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9IiMwMDJENjQiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMwMDJENjQiIHN0b3Atb3BhY2l0eT0iMCIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IHgxPSIuNSIgeTE9IjAiIHgyPSIuNSIgeTI9Ii41IiBpZD0iZSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwMkQ2NCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzAwMkQ2NCIgc3RvcC1vcGFjaXR5PSIwIi8+PC9saW5lYXJHcmFkaWVudD48bWFzayBpZD0iYiIgc3R5bGU9Im1hc2stdHlwZTphbHBoYSIgbWFza1VuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGggZD0iTTAgMTIwaDI5MFYwSDB2MTIwWiIgZmlsbD0iI0ZGRiIvPjwvbWFzaz48L2RlZnM+PHBhdGggZD0iTTAgMjUwaDI5MFYwSDB2MjUwWiIgZmlsbD0iIzE5NTI4RiIvPjxwYXRoIGQ9Ik0wIDI1MGgyOTBWMEgwdjI1MFoiIGZpbGw9InVybCgjYSkiLz48ZyBtYXNrPSJ1cmwoI2IpIj48Y2lyY2xlIGN4PSI2MC41IiBjeT0iMTE1LjUiIGZpbGw9InVybCgjYykiIHI9IjIwMC41IiBzdHlsZT0ib3BhY2l0eTouMjAwMDAwMDAyOTgwMjMyMjQiLz48Y2lyY2xlIGN4PSI2MC45NTciIGN5PSIxMTUuOTU3IiBmaWxsPSJ1cmwoI2QpIiByPSIxMjkuNzA4IiBzdHlsZT0ib3BhY2l0eTouMzAwMDAwMDExOTIwOTI4OTYiLz48ZWxsaXBzZSBjeD0iNjAuNSIgY3k9IjExNS45NTciIHJ4PSI2NC4zOTciIHJ5PSI2My45NDEiIGZpbGw9InVybCgjZSkiIHN0eWxlPSJvcGFjaXR5Oi4zMDAwMDAwMTE5MjA5Mjg5NiIvPjwvZz48L3N2Zz4=");
background-repeat: no-repeat;
background-size: cover;
padding: 40rpx;
color: #fff;
border-radius: 18rpx;
margin-right: 30rpx;
&:nth-child(1) {
margin-left: 40rpx;
}
&.week-movie{
background-image: url(https://img1.doubanio.com/view/photo/photo/public/p2917337389.jpg);
}
&.douban-top {
background-image: url("https://img1.doubanio.com/view/photo/photo/public/p456482220.jpg")
}
.card-num{
font-size: 22rpx;
margin-bottom: 4rpx;
}
.card-title {
margin-bottom: 40rpx;
.card-text {
font-size: 42rpx;
font-weight: 500;
}
}
.list .item {
display: flex;
margin-bottom: 20rpx;
align-items: center;
.rank {
font-size: 24rpx;
margin-right: 30rpx;
}
image {
width: 60rpx;
height: 84rpx;
margin-right: 24rpx;
border-radius: 12rpx;
}
.info {
.title {
font-size: 30rpx;
margin-bottom: 8rpx;
}
}
}
}
}
</style>
RecDianying.vue
js
<template>
<view class="rec">
<scroll-view scroll-x="auto">
<view class="list" :style="{ width: 610 * recListRef.length + 'rpx'}">
<view class="card" v-for="item in recListRef" :key="item.id">
<view class="img-wrap">
<image :src="item.image"></image>
</view>
<view class="info">
<text class="title">{{ item.title}}</text>
<view class="desc">
<text>共{{ item.partNumber }}部</text>
<text>{{ item.follows }}人关注</text>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { recList} from '@/pages/index/data/data.js'
const recListRef = ref(recList)
</script>
<style lang="scss" scoped>
.rec {
margin-top: 100rpx;
}
.list {
display: flex;
.card {
padding: 30rpx;
border-radius: 18rpx;
width: 580rpx;
margin-right: 30rpx;
display: flex;
background: rgba(114, 114, 114, 0.12);
&:nth-child(1) {
margin-left: 40rpx;
}
.img-wrap {
width: 200rpx;
height: 200rpx;
border-radius: 12rpx;
margin-right: 40rpx;
image {
width: 100%;
height: 100%;
}
}
.info {
flex: 1;
.title {
display: block;
font-size: 38rpx;
padding-bottom: 52rpx;
}
.desc {
font-size: 26rpx;
color: #818181;
display: flex;
justify-content: space-between;
}
}
}
}
</style>
FindDianying.
js
<template>
<view class="find-movies">
<view class="title">
找电影
</view>
<view class="list">
<view class="item" v-for="item in findMoviesRef" :key="item.id">
<view class="img-wrap">
<image :src="item.image"></image>
</view>
<view class="info">
<view class="top">
<view class="text-wrap">
<view class="title-wrap">
<text class="title">{{ item.title }}</text>
<text class="year">({{ item.fullYear }})</text>
</view>
<uni-rate v-model="item.rate" :size="11" class="rate"></uni-rate>
<view class="desc">{{item.desc}}</view>
</view>
<view class="control">
<view class="love-icon"></view>
<text>爱心</text>
</view>
</view>
<view class="bottom">你可能感兴趣</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { findMovies } from '@/pages/index/data/data.js'
const findMoviesRef = ref(findMovies)
</script>
<style lang="scss" scoped>
.title {
font-size: 42rpx;
color: #191919;
margin-bottom: 80rpx;
}
.find-movies {
margin-top: 100rpx;
padding: 0 40rpx;
}
.list .item {
display: flex;
margin-bottom: 60rpx;
padding-bottom: 40rpx;
border-bottom: 1rpx solid #dfdfdf;
.img-wrap{
width: 160rpx;
height: 224rpx;
border-radius: 12rpx;
overflow: hidden;
margin-right: 30rpx;
image {
width: 100%;
height: 100%;
}
}
.info {
flex: 1;
}
.top {
display: flex;
align-items: center;
.text-wrap{
flex: 1;
margin-right: 80rpx;
.title-wrap{
.title {
font-size: 34rpx;
font-weight: 700;
}
.year {
color: rgb(129, 129, 129)
}
}
.rate {
margin: 8rpx 0;
}
.desc {
color: #818181;
font-size: 26rpx;
line-height: 44rpx;
}
}
.control {
width: 54rpx;
font-size: 26rpx;
color: #f90;
.love-icon {
width: 48rpx;
height: 48rpx;
background: url(/static/red-xin.svg);
}
}
}
.bottom {
margin-top: 20rpx;
border-radius: 12rpx;
background: #f7f7f7;
color: #818181;
font-size: 26rpx;
padding: 0 20rpx;
line-height: 80rpx;
}
}
</style>
data.js
js
const topList = [
{
id: 1,
title: '荒蛮故事',
image: 'https://img3.doubanio.com/view/photo/m_ratio_poster/public/p2919686972.jpg',
rate: 5
},
{
id: 2,
title: '孤独的美食家 剧场版',
image: 'https://img2.doubanio.com/view/photo/m_ratio_poster/public/p2919802971.jpg',
rate: 5
},
{
id: 3,
title: '穷养攻略',
image: 'https://img3.doubanio.com/view/photo/m_ratio_poster/public/p2920147657.jpg',
rate: 5
},
{
id: 4,
title: '触碰你',
image: 'https://img3.doubanio.com/view/photo/m_ratio_poster/public/p2920288412.jpg',
rate: 5
}
]
const topList2 = [
{
id: 1,
title: '孤独的美食家 剧场版',
image: 'https://img2.doubanio.com/view/photo/m_ratio_poster/public/p2919802971.jpg',
rate: 5
},
{
id: 2,
title: '此心安处',
image: 'https://img3.doubanio.com/view/photo/m_ratio_poster/public/p2919083962.jpg',
rate: 5
},
{
id: 3,
title: '黑道中人',
image: 'https://img9.doubanio.com/view/photo/m_ratio_poster/public/p2917445884.jpg',
rate: 5
},
{
id: 4,
title: '罪人',
image: 'https://img9.doubanio.com/view/photo/m_ratio_poster/public/p2919706584.jpg',
rate: 5
},
{
id: 5,
title: '战·争',
image: 'https://img3.doubanio.com/view/photo/m_ratio_poster/public/p2918622737.jpg',
rate: 5
}
]
const hotList = [
{
id: 1,
image: 'https://img2.doubanio.com/view/photo/s_ratio_poster/public/p2919802971.jpg',
title: '孤独的美食家 剧场版',
rate: 5
},
{
id: 2,
image: 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2919686972.jpg',
title: '荒蛮故事',
rate: 5
},
{
id: 3,
image: 'https://img1.doubanio.com/view/photo/photo/public/p456482220.jpg',
title: '黎明的一切',
rate: 5
}
]
const weekMovies =[
{
id: 1,
image: 'https://img2.doubanio.com/view/photo/s_ratio_poster/public/p2919802971.jpg',
title: '孤独的美食家 剧场版',
rate: 5
},
{
id: 2,
image: 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2919686972.jpg',
title: '昨日青春',
rate: 5
},
{
id: 3,
image: 'https://img1.doubanio.com/view/photo/photo/public/p456482220.jpg',
title: '黎明的一切',
rate: 5
}
]
const doubanTops = [
{
id: 1,
image: 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg',
title: '肖申克的救赎',
rate: 5
},
{
id: 2,
image: 'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2561716440.jpg',
title: '霸王别姬',
rate: 5
},
{
id: 3,
image: 'https://img9.doubanio.com/view/photo/s_ratio_poster/public/p457760035.jpg',
title: '泰坦尼克号',
rate: 5
}
]
const recList = [
{
id: 1,
image: 'https://img9.doubanio.com/dae/merged_cover/img_handler/chart_cover/round_rec/ECKQ74M7Y-20250401155555_2025-04-14',
title: '2025年04月定档热门电影推荐',
partNumber: 30,
follows: 3000
},
{
id: 1,
image: 'https://img1.doubanio.com/dae/screenshot/image/v2/html/cos_f27f9c4522c419e4/profile/chart_cover_url',
title: '豆瓣2024评分最高华语电影',
partNumber: 30,
follows: 3000
},
{
id: 1,
image: 'https://img1.doubanio.com/dae/screenshot/image/v2/html/cos_686319d3933dc894/profile/chart_cover_url',
title: '豆瓣2024评分最高外语电影',
partNumber: 30,
follows: 3000
},
{
id: 1,
image: 'https://img1.doubanio.com/dae/screenshot/image/v2/html/cos_45ad4da8757681c3/profile/chart_cover_url',
title: '豆瓣2024冷门佳片',
partNumber: 30,
follows: 3000
}
]
const findMovies = [
{
id: 1,
title: '异国日记',
image: 'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2906943779.jpg',
rate: 5,
desc: '2024 / 日本 / 剧情 / 濑田夏希 / 新垣结衣 早濑憩',
fullYear: 2024
},
{
id: 2,
title: '大都市的爱情法',
image: 'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2913590069.jpg',
rate: 5,
desc: '2024 / 韩国 / 剧情 喜剧 爱情 同性 / 李彦禧 / 金高银 卢尚贤',
fullYear: 2024
},
{
id: 3,
title: '从21世纪安全撤离',
image: 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2911256273.jpg',
rate: 5,
desc: '2024 / 中国大陆 / 喜剧 科幻 / 李阳 / 张若昀 钟楚曦',
fullYear: 2024
},
{
id: 4,
title: '房子',
image: 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2915530907.jpg',
rate: 5,
desc: '2024 / 西班牙 / 剧情 喜剧 传记 / 阿力克斯·蒙托亚 / 大卫·贝尔达格尔 路易斯·卡叶赫',
fullYear: 2024
},
{
id: 5,
title: '我的新朋友',
image: 'https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2909335684.jpg',
rate: 5,
desc: '2024 / 法国 / 剧情 / 安德烈·泰希内 / 伊莎贝尔·于佩尔 阿弗西娅·埃尔奇',
fullYear: 2024
},
]
export {
topList,
topList2,
hotList,
weekMovies,
doubanTops,
recList,
findMovies
}
index.vue
js
<template>
<view class="content">
<TopDianyingVue></TopDianyingVue>
<LangCateVue></LangCateVue>
<HotDianyingVue></HotDianyingVue>
<RecDianyingVue></RecDianyingVue>
<FindDianyingVue></FindDianyingVue>
</view>
</template>
<script setup>
import TopDianyingVue from './components/TopDianying.vue';
import LangCateVue from './components/LangCate.vue';
import HotDianyingVue from './components/HotDianying.vue';
import FindDianyingVue from './components/FindDianying.vue';
import RecDianyingVue from './components/RecDianying.vue';
</script>
<style>
</style>
根目录下的pages.json
js
{
"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "豆瓣电影"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "white",
"navigationBarTitleText": "豆瓣电影",
"navigationBarBackgroundColor": "#17c544",
"backgroundColor": "#17c544"
},
"uniIdRouter": {}
}
这是一个非常重要的配置文件,在这个文件中:
- globalStyle 是一个全局样式的配置
- navigationBarTextStyle 配置标题栏标题的颜色,只能有两个选项,white和black
- navigationBarTitleText 标题栏的文本
- navigationBarBackgroundColor 标题栏的背景色
- pages 路由相关的配置
- path 配置页面路径
- style 下面的navigationBarTitleText 配置标题栏的文本,会覆盖globalStyle中的navigationBarTitleText
配置微信开发者工具运行路径: HBuilderX 顶部 运行 -> 运行到小程序模拟器 -> 运行设置, 然后找到微信开发者工具路径,填写路径即可

现在就可以运行我们开发的小程序了。运行 -> 运行到小程序 - 微信开发者工具, 这个时候Hbuidler 就会开始编译,编译完成会自动打开微信开发者工具,这时候我们就能看到项目的效果了。

我们可以点击微信开发者工具的预览,到手机微信上查看真实的效果。但是会发现预览按钮是禁用点击的
这是什么原因呢?因为没填写appid 的原因,我们怎么去添加appid 呢? 这时候可能有些开发者会想在微信开发者里面直接改, 这样合理吗? 肯定是不合理的,因为我们是在HBuilder X上开发的,微信开发者工具只是我们用来看效果的一个工具。所以我们应该到HBuilder X 去修改,打开manifest.json,选择微信小程序配置,在这里就可以填写微信小程序的appid了
没有小程序appid 的可以根据微信官方的教程自己创建一个,这是微信小程序创建appid 的官方文档developers.weixin.qq.com/miniprogram...
这个时候就可以点击预览,扫面弹出来的二维码就可以在手机微信上查看我们开发出来的豆瓣电影小程序了。
手机预览效果


到这里我们就基本上完成了一个微信小程序的开发。但是认真的同学可能会发现,点击预览的时候在控制台有两个红色的未通过。
怎么处理这两个问题呢?首先解决第一个问题,对JS文件进行压缩。 在HBuilder X 中,打开manifest.json, 选择微信小程序配置, 将上传代码是自动压缩这个选项选中。即可解决第一个问题

第二个问题该怎么解决呢?还是打开manifest.json, 找到源码视图,然后找到mp-weixin, 添加上"lazyCodeLoading" : "requiredComponents"
即可。

这个时候我们点击 运行 -> 运行到小程序模拟器 -> 停止微信开发者工具。 然后再 运行 -> 运行到小程序模拟器 -> 微信开发者工具。 也就是重新运行下,然后在微信开发者工具中,重新点击预览。这个时候就会发现那两个问题已经解决了


这样我们就完整的开发完了一个豆瓣电影的微信小程序。
uniapp 是跨平台的,除了可以运行到小程序还可以运行到浏览器,也就是传说中的h5, 点击运行 -> 运行到浏览器 -> chrome 就可以在浏览器中看到效果了。
你会发现有些图片没显示,别惊慌,这不是我们代码的问题,这是豆瓣的服务器对图片资源做了一些访问权限处理。你只需要把图片下载到本地或者上传到自己的服务器就可以解决了。这样我们就瞬间就开发完了一个h5,效率是不是瞬间提升上来了。
五、总结:
本篇主要介绍了,uni-app 项目的开发环境搭建,基础组件的使用,扩展组件的使用,通过开发一个豆瓣微信小程序和h5 提升对uni-app 运用实践。还介绍了在预览过程中遇到预览按钮不能点击的解决方案,还介绍了预览控制台出现了两个代码质量问题的解决方案。