随着移动互联网的飞速发展,跨平台应用开发的需求日益增长。uniapp作为一种使用Vue.js开发所有前端应用的框架,因其便捷性和高效性受到了广大开发者的青睐。我经过一段时间的学习和实践,对uniapp有了更深入的了解,下面是我的—些学习心得。
在学习uniapp的过程中,我首先了解了其基本的概念和特性。uniapp通过编译到不同的平台来生成对应平台的原生应用,这大大简化了跨平台开发的复杂性。同时,它兼容多端运行,无论是iOS还是Android,甚至是Web端,都能轻松应对。这种统一的开发方式不仅提高了开发效率,也降低了维护成本。
在学习过程中,我遇到了不少挑战。其中最大的挑战在于理解并掌握uniapp的组件和API。这些组件和API是实现各种功能的关键,但它们的种类繁多,且在不同平台上的表现也可能存在差异。为了克服这些困难,我反复查阅官方文档,参与社区讨论,通过实践不断加深理解。
以下是我在学习过程中的自我练习:
1.这是一个购物小程序,没有过多完善,只做了基本的主页内容
<template>
<view class="content">
<uni-swiper-dot :dots-styles="dotsStyles" :info="bannerList" :current="current" field="content" :mode="mode">
<swiper class="swiper-box" @change="change">
<swiper-item v-for="(item,index) in bannerList" :key="index">
<view class="swiper-item">
<image :src="item.url" mode=""></image>
</view>
</swiper-item>
</swiper>
</uni-swiper-dot>
<u-sticky bgColor="#fff">
<u-tabs :list="tabs"></u-tabs>
</u-sticky>
<view class="List">
<uni-list v-for="(item,index) in list" :key="item.id">
<view class="good">
<view class="left">
<image class="img" :src="item.goodImg" mode=""></image>
</view>
<view class="right">
<view class="name">{{item.goodName}}</view>
<text class="price" style="color: red;">{{item.goodPrice}}元</text>
<text class="sold">已售{{item.goodSold}}件</text>
</view>
</view>
</uni-list>
</view>
</view>
</template>
<script>
export default{
data() {
return{
list:[],
bannerList:[],
current:0,
mode:'round',
dotsStyles:{
selectedBackgroundColor:"#ffffff",
selectedBorder:"#ffffff"
},
tabs:[{
name:'全部',
},{
name:'母婴',
},{
name:'图书'
}]
}
},
onLoad() {
this.getBanner();
this.getList();
},
methods: {
change(e) {
this.current=e.detail.current;
},
getBanner() {
uni.request({
url:"http://106.52.94.26:9088/MobileShop/carousel",
method:'GET',
success: (res) => {
console.log(res);
this.bannerList=res.data
}
})
},
getList() {
uni.request({
url:"http://106.52.94.26:9088/MobileShop/goods",
method:'GET',
success: (res) => {
console.log((res));
this.list=res.data.sort((a,b) => a.id-b.id);
}
})
}
}
}
</script>
<style lang="scss">
.content{
.swiper-box{
image{
width: 100%;
}
}
/deep/ .u-tabs__wrapper__nav__item{
flex: 1;
}
.List{
.good{
display: flex;
align-items: center;
}
.left{
.img{
width: 250rpx;
height: 290rpx;
}
}
.right{
.name{
margin-top: 10rpx;
font-size: 30rpx;
margin-bottom: 15rpx;
}
.price{
font-size: 30rpx;
margin-right: 15rpx;
}
}
}
}
</style>
效果图:
以上为主页内容,其他当时还在学习,没来及的 做更多
2.这次是一个电影小程序,依旧只做了主页和详情页练手
<template>
<!-- template里面的跟标签只能有一个 -->
<view class="index">
<view class="search">
<text class="iconfont icon-search"></text>
<text @tap="ToSearch()">搜索电影、电视、综艺等</text>
</view>
<!-- 轮播图 -->
<swiper class="banner" :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000">
<swiper-item>
<image src="../../static/di.jpg" mode=""></image>
</swiper-item>
<swiper-item>
<image src="../../static/img/user/avatar.jpg" mode=""></image>
</swiper-item>
<swiper-item>
<image src="../../static/di.jpg" mode=""></image>
</swiper-item>
</swiper>
<!-- <navigator open-type="switchTab" url="/pages/my/my">跳转</navigator> -->
<!-- <navigator open-type="navigate" url="/pages/search/search">跳转</navigator> -->
<!-- <button @tap="ToSearch">跳转到搜索页面</button> -->
<!-- <button @tap="ToMy">跳转到我的页面</button> -->
<view class="movie">
<view class="title">
电影
</view>
<view class="list">
<view class="item" @tap="ToDetail(item.id)" v-for="(item,index) in list" :key="item.id">
<image class="img" :src="item.imgUrl" mode=""></image>
<text>{{item.title}}</text>
</view>
</view>
</view>
</view>
</template>
<script>
//import "../../common/js/index.js"
// import movie from"../../common/js/movies.js"
export default {
data() {
return {
list:[],
bannerlist:[]
}
},
onLoad() {
// this.list=movie;
// console.log(this.list)
this.getList();
this.getBannerList();
},
methods: {
ToSearch(){
uni.navigateTo({
url:"/pages/search/search"
})
},
ToMy(){
uni.switchTab({
url:"/pages/my/my"
})
},
ToDetail(id){
uni.navigateTo({
url:`/pages/movie-detail/movie-detail?id=${id}&name=list&age=18`
})
},
getBannerList(){
uni.request({
url:"http://106.52.94.26:9088/movies/carousel",
method:'GET',
success: (res) => {
console.log(res);
this.bannerlist=res.data.data;
}
})
},
getList(){
uni.request({
url:"http://106.52.94.26:9088/movies/list",
method:'GET',
success: (res) => {
console.log(res);
this.list=res.data.data;
}
})
}
}
}
</script>
<style lang="scss">
/* @import url("@commons/index.css"); */
/* 新的尺寸单位 rpx */
.movie{
margin: 10px;
.title{
color: #0a9d14;
font-size: 40rpx;
margin-bottom: 10px;
}
.list{
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.item{
width: 32%;
text-align: center;
margin-bottom: 10px;
image{
width: 100%;
height: 300rpx;
border-radius: 8px;
}
text{
color:#6b6b6b
}
}
}
}
.search{
background-color: #f2f2f2;
height: 75rpx;
line-height: 75rpx;
border-radius: 10rpx;
margin: 20rpx 30rpx;
}
.search .iconfont{
margin: 0 8px;
}
.banner{
height: 220px;
}
.banner image{
width: 100%;
height: 220px;
}
</style>
主页效果图:
这是详情页内容;
<template>
<view class="detail">
<view class="bg" :style="'background-image: url('+detail.imgUrl+')'"></view>
<view class="big-box">
<image :src="detail.imgUrl" mode=""></image>
<view class="introduction">
<view>{{detail.title}}</view>
<view>{{detail.years}}/{{detail.area}}</view>
<view>{{detail.director}}/{{detail.actor}}</view>
</view>
<!-- 剧情简介 -->
<view class="introduce">
<view class="title">
剧情简介:
</view>
<view class="desc">
<text v-if="isShowAll">{{detail.desc}}</text>
<text v-else>{{detail.desc.substr(0,85)}}...</text>
<text v-if="isShowAll" @tap="isShowAll=false" style="color: blue;">收起</text>
<text v-else @tap="isShowAll=true" style="color: blue;">全文</text>
</view>
</view>
<!-- 播放源 -->
<view class="source">
<view class="title">
播放源:
</view>
<view class="list">
<view @tap="toVideo(item.Url)" class="item" v-for="(item,index) in detail.sources" :key="index">
<text>{{item.Name}}</text>
<text class="iconfont icon-arrow-right"></text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import movie from "../../common/js/movies.js";
export default {
data() {
return {
id:"",
detail:null,
isShowAll:false
}
},
onLoad(option){
console.log(option)
this.id=option.id;
this.getDetail()
},
methods:{
getDetail(){
movie.filter(item=>{
if(item.id==this.id){
this.detail=item;
console.log(item);
}
});
},
toVideo(url){
uni.navigateTo({
url:"/pages/movie-detail/video?path="+url
})
}
}
}
</script>
<style lang="scss">
.detail{
.bg{
background-repeat: no-repeat;
background-size: 100% 100%;
filter: blur(20px);
height: 100vh;
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
.big-box{
position: relative;
color: white;
height: 350px;
text-align: center;
image{
width: 250px;
height: 300px;
margin-top: 25px;
}
.introduction{
line-height: 1.5;
font-weight: 700;
font-size: 15px;
}
}
.introduce{
position: relative;
margin-top: 50px;
color: #ffffff;
.title{
font-weight: 700;
font-size: 20px;
color: #dfc196;
margin-bottom: 15px;
text-align: left;
}
.desc{
font-weight: 700;
line-height: 20px;
font-size: 15px;
}
}
.source{
margin: 10px;
.title{
font-weight: bold;
font-size: 40rpx;
color: #df834e;
text-align: left;
}
.list{
.item{
background-color: #ffffff;
color: #333;
display: flex;
justify-content: space-between;
padding: 20px;
margin-bottom: 10px;
}
}
}
}
</style>
详情页效果图:
播放页内容:
<template>
<view>
<web-view :src="url"></web-view>
</view>
</template>
<script>
export default {
data() {
return {
url:""
}
},
onLoad(option) {
this.url=option.path
},
methods: {
}
}
</script>
<style>
</style>
这里是电影内容文件,需要可自取:
const list = [{
"episodes_info": "",
"rate": "9.7",
"cover_x": 2000,
"title": "肖申克的救赎",
"playable": true,
"id": "1292052",
"cover_y": 2963,
"is_new": false,
"director": "弗兰克·德拉邦特",
"actor": "蒂姆·罗宾斯/摩根·弗里曼/鲍勃·冈顿/威廉姆·赛德勒",
"area": "美国",
"desc": "一场谋杀案使银行家安迪(蒂姆•罗宾斯 Tim Robbins 饰)蒙冤入狱,谋杀妻子及其情人的指控将囚禁他终生。在肖申克监狱的首次现身就让监狱“大哥”瑞德(摩根•弗里曼 Morgan Freeman 饰)对他另眼相看。瑞德帮助他搞到一把石锤和一幅女明星海报,两人渐成患难 之交。很快,安迪在监狱里大显其才,担当监狱图书管理员,并利用自己的金融知识帮助监狱官避税,引起了典狱长的注意,被招致麾下帮助典狱长洗黑钱。偶然一次,他得知一名新入狱的小偷能够作证帮他洗脱谋杀罪。燃起一丝希望的安迪找到了典狱长,希望他能帮自己翻案。阴险伪善的狱长假装答应安迪,背后却派人杀死小偷,让他唯一能合法出狱的希望泯灭。沮丧的安迪并没有绝望,在一个电闪雷鸣的风雨夜,一场暗藏几十年的越狱计划让他自我救赎,重获自由!老朋友瑞德在他的鼓舞和帮助下,也勇敢地奔向自由。 本片获得1995年奥斯卡10项提名,以及金球奖、土星奖等多项提名。",
"years": "1994",
"sources": [{
"Name": "爱奇艺视频",
"Url": "http://www.iqiyi.com/v_19rra0h3wg.html?vfm=m_331_dbdy&fv=4904d94982104144a1548dd9040df241"
},
{
"Name": "腾讯视频",
"Url": "http://v.qq.com/x/cover/1o29ui77e85grdr.html?ptag=douban.movie"
},
{
"Name": "优酷视频",
"Url": "http://v.youku.com/v_show/id_XMjgwNDkwNzE2.html?tpa=dW5pb25faWQ9MzAwMDA4XzEwMDAwMl8wMl8wMQ&refer=esfhz_operation.xuka.xj_00003036_000000_FNZfau_19010900"
},
{
"Name": "哔哩哔哩",
"Url": "https://m.bilibili.com/bangumi/play/ss28274?bsource=doubanh5"
}
],
"imgUrl": "http://s9k8pe75c.hd-bkt.clouddn.com/p480747492.webp?e=1709113916&token=VVKWxI7zpGcuO5gCjDZAfdmZMPQ4jOj_09JHkB_S:S6ovOMHuqwEK9rYHeiwu42TVqOY=",
"cateName": "电影",
"catId": 0
},
{
"episodes_info": "",
"rate": "8.3",
"cover_x": 1882,
"title": "流浪地球2",
"playable": true,
"id": "35267208",
"cover_y": 2800,
"is_new": false,
"director": "郭帆",
"actor": "吴京/刘德华/李雪健/沙溢",
"area": "中国大陆",
"desc": "太阳即将毁灭,人类在地球表面建造出巨大的推进器,寻找新的家园。然而宇宙之路危机四伏,为了拯救地球,流浪地球时代的年轻人再次挺身而出,展开争分夺秒的生死之战。",
"years": "2023",
"sources": [{
"Name": "咪咕视频",
"Url": "https://m.miguvideo.com/mgs/msite/prd/detail.html?cid=793668451&pwId=d01197d3076b4164af82983c408bb996"
},
{
"Name": "腾讯视频",
"Url": "http://v.qq.com/x/cover/mzc002008v8rka3.html?ptag=douban.movie"
},
{
"Name": "芒果TV",
"Url": "http://www.mgtv.com/b/353601/18642419.html?cxid=vb4rv4jhk"
},
{
"Name": "爱奇艺视频",
"Url": "http://www.iqiyi.com/v_1yzsojq1cg8.html?vfm=m_331_dbdy&fv=4904d94982104144a1548dd9040df241"
},
{
"Name": "优酷视频",
"Url": "http://v.youku.com/v_show/id_XNTk1NDg3ODQ1Ng==.html?tpa=dW5pb25faWQ9MzAwMDA4XzEwMDAwMl8wMl8wMQ&refer=esfhz_operation.xuka.xj_00003036_000000_FNZfau_19010900"
},
{
"Name": "1905电影网",
"Url": "http://vip.1905.com/play/1628041.shtml?__hz=6e0721b2c6977135&api_source=douban_vodadd"
},
{
"Name": "哔哩哔哩",
"Url": "https://m.bilibili.com/bangumi/play/ss44847?bsource=doubanh5"
}
],
"imgUrl": "http://s9k8pe75c.hd-bkt.clouddn.com/p2885955777.webp?e=1709114011&token=VVKWxI7zpGcuO5gCjDZAfdmZMPQ4jOj_09JHkB_S:0dI9fE98xlrvXa5pmJyBWIOI8z4=",
"cateName": "电影",
"catId": 0
},
{
"episodes_info": "",
"rate": "9.0",
"cover_x": 2810,
"title": "我不是药神",
"playable": true,
"id": "26752088",
"cover_y": 3937,
"is_new": false,
"director": "文牧野",
"actor": "徐峥/王传君/周一围/谭卓",
"area": "中国大陆",
"desc": "普通中年男子程勇(徐峥 饰)经营着一家保健品店,失意又失婚。不速之客吕受益(王传君 饰)的到来,让他开辟了一条去印度买药做“代购”的新事业,虽然困难重重,但他在这条“买药之路”上发现了商机,一发不可收拾地做起了治疗慢粒白血病的印度仿制药独家代理商。赚钱的同时,他也认识了几个病患及家属,为救女儿被迫做舞女的思慧(谭卓 饰)、说一口流利“神父腔”英语的刘牧师(杨新鸣 饰),以及脾气暴烈的“黄毛”(章宇 饰),几个人合伙做起了生意,利润倍增的同时也危机四伏。程勇昔日的小舅子曹警官(周一围 饰)奉命调查仿制药的源头,假药贩子张长林(王砚辉 饰)和瑞士正牌医药代表(李乃文 饰)也对其虎视眈眈,生意逐渐变成了一场关于救赎的拉锯战。 本片改编自慢粒白血病患者陆勇代购抗癌药的真实事迹。",
"years": "2018",
"sources": [{
"Name": "咪咕视频",
"Url": "https://m.miguvideo.com/mgs/msite/prd/detail.html?cid=649118258&pwId=d01197d3076b4164af82983c408bb996"
},
{
"Name": "爱奇艺视频",
"Url": "http://www.iqiyi.com/v_19rreozmq8.html?vfm=m_331_dbdy&fv=4904d94982104144a1548dd9040df241"
},
{
"Name": "腾讯视频",
"Url": "http://v.qq.com/x/cover/og0eputlxwet1cn.html?ptag=douban.movie"
},
{
"Name": "芒果TV",
"Url": "http://www.mgtv.com/b/323492/4705829.html?cxid=vb4rv4jhk"
},
{
"Name": "优酷视频",
"Url": "http://v.youku.com/v_show/id_XMzgzOTgyMzc4MA==.html?tpa=dW5pb25faWQ9MzAwMDA4XzEwMDAwMl8wMl8wMQ&refer=esfhz_operation.xuka.xj_00003036_000000_FNZfau_19010900"
},
{
"Name": "1905电影网",
"Url": "http://vip.1905.com/play/1348058.shtml?__hz=6e0721b2c6977135&api_source=douban_vodadd"
}
],
"imgUrl": "http://s9k8pe75c.hd-bkt.clouddn.com/p2561305376.webp?e=1709114192&token=VVKWxI7zpGcuO5gCjDZAfdmZMPQ4jOj_09JHkB_S:RTPD1aiCa9_AEsqM9XAg0Do3eaA=",
"cateName": "电影",
"catId": 0
},
{
"episodes_info": "",
"rate": "9.2",
"cover_x": 1080,
"title": "疯狂动物城",
"playable": true,
"id": "25662329",
"cover_y": 1663,
"is_new": false,
"director": "拜伦·霍华德",
"actor": "金妮弗·古德温/杰森·贝特曼/伊德里斯·艾尔巴/珍妮·斯蕾特",
"area": "美国",
"desc": "故事发生在一个所有哺乳类动物和谐共存的美好世界中,兔子朱迪(金妮弗·古德温 Ginnifer Goodwin 配音)从小就梦想着能够成为一名惩恶扬善的刑警,凭借着智慧和努力,朱迪成功的从警校中毕业进入了疯狂动物城警察局,殊不知这里是大型肉食类动物的领地,作为第一只,也是唯一的小型食草类动物,朱迪会遇到怎样的故事呢? 近日里,城中接连发生动物失踪案件,就在全部警员都致力于调查案件真相之时,朱迪却被局长(伊德瑞斯·艾尔巴 Idris Elba 配音)发配成为了一名无足轻重的交警。某日,正在执勤的兔子遇见了名为尼克(杰森·贝特曼 Jason Bateman 配音)的狐狸,两人不打不相识,之后又误打误撞的接受了寻找失踪的水獭先生的任务,如果不能在两天之内找到水獭先生,朱迪就必须自愿离开警局。朱迪找到了尼克,两人联手揭露了一个隐藏在疯狂动物城之中的惊天秘密。",
"years": "2016",
"sources": [{
"Name": "咪咕视频",
"Url": "https://m.miguvideo.com/mgs/msite/prd/detail.html?cid=701106113&pwId=d01197d3076b4164af82983c408bb996"
},
{
"Name": "腾讯视频",
"Url": "http://v.qq.com/x/cover/fhe2h7sop52qzza.html?ptag=douban.movie"
}
],
"imgUrl": "http://s9k8pe75c.hd-bkt.clouddn.com/p2614500649.webp?e=1709114245&token=VVKWxI7zpGcuO5gCjDZAfdmZMPQ4jOj_09JHkB_S:vvzJrA55M50Pf1TtshhC3Ulfq7Y=",
"cateName": "电影",
"catId": 0
},
{
"episodes_info": "",
"rate": "9.4",
"cover_x": 1080,
"title": "千与千寻",
"playable": false,
"id": "1291561",
"cover_y": 1560,
"is_new": false,
"director": "宫崎骏",
"actor": "柊瑠美/入野自由/夏木真理/菅原文太",
"area": "日本",
"desc": "千寻和爸爸妈妈一同驱车前往新家,在郊外的小路上不慎进入了神秘的隧道——他们去到了另外一个诡异世界—一个中世纪的小镇。远处飘来食物的香味,爸爸妈妈大快朵颐,孰料之后变成了猪!这时小镇上渐渐来了许多样子古怪、半透明的人。 千寻仓皇逃出,一个叫小白的人救了他,喂了她阻止身体消 失的药,并且告诉她怎样去找锅炉爷爷以及汤婆婆,而且必须获得一份工作才能不被魔法变成别的东西。 千寻在小白的帮助下幸运地获得了一份在浴池打杂的工作。渐渐她不再被那些怪模怪样的人吓倒,并从小玲那儿知道了小白是凶恶的汤婆婆的弟子。 一次,千寻发现小白被一群白色飞舞的纸人打伤,为了救受伤的小白,她用河神送给她的药丸驱出了小白身体内的封印以及守封印的小妖精,但小白还是没有醒过来。 为了救小白,千寻又踏上了她的冒险之旅。",
"years": "2019",
"sources": [],
"imgUrl": "http://s9k8pe75c.hd-bkt.clouddn.com/p2614500649.webp?e=1709114245&token=VVKWxI7zpGcuO5gCjDZAfdmZMPQ4jOj_09JHkB_S:vvzJrA55M50Pf1TtshhC3Ulfq7Y=",
"cateName": "电影",
"catId": 0
},
{
"episodes_info": "",
"rate": "9.5",
"cover_x": 2349,
"title": "泰坦尼克号",
"playable": true,
"id": "1292722",
"cover_y": 3480,
"is_new": false,
"director": "詹姆斯·卡梅隆",
"actor": "莱昂纳多·迪卡普里奥/凯特·温丝莱特/比利·赞恩/凯西·贝茨",
"area": "美国 / 墨西哥",
"desc": "1912年4月10日,号称 “世界工业史上的奇迹”的豪华客轮泰坦尼克号开始了自己的处女航,从英国的南安普顿出发驶往美国纽约。富家少女罗丝(凯特•温丝莱特)与母亲及未婚夫卡尔坐上了头等舱;另一边,放荡不羁的少年画家杰克(莱昂纳多·迪卡普里奥)也在码头的一场赌博中赢得了下等舱的船票。 罗丝厌倦了上流社会虚伪的生活,不愿嫁给卡尔,打算投海自尽,被杰克救起。很快,美丽活泼的罗丝与英俊开朗的杰克相爱,杰克带罗丝参加下等舱的舞会、为她画像,二人的感情逐渐升温。 1912年4月14日,星期天晚上,一个风平浪静的夜晚。泰坦尼克号撞上了冰山,“永不沉没的”泰坦尼克号面临沉船的命运,罗丝和杰克刚萌芽的爱情也将经历生死的考验。",
"years": "1998",
"sources": [{
"Name": "爱奇艺视频",
"Url": "http://www.iqiyi.com/v_19rrny4w8w.html?vfm=m_331_dbdy&fv=4904d94982104144a1548dd9040df241"
},
{
"Name": "腾讯视频",
"Url": "http://v.qq.com/x/cover/t5jqhgw8pix81mw.html?ptag=douban.movie"
},
{
"Name": "芒果TV",
"Url": "http://www.mgtv.com/b/49027/592751.html?cxid=vb4rv4jhk"
}
],
"imgUrl": "http://s9k8pe75c.hd-bkt.clouddn.com/p457760035.webp?e=1709114378&token=VVKWxI7zpGcuO5gCjDZAfdmZMPQ4jOj_09JHkB_S:dMqPztG2FBi1BNsxgMZwduiW2sQ=",
"cateName": "电影",
"catId": 0
},
{
"episodes_info": "",
"rate": "9.5",
"cover_x": 1872,
"title": "阿甘正传",
"playable": true,
"id": "1292720",
"cover_y": 2546,
"is_new": false,
"director": "罗伯特·泽米吉斯",
"actor": "汤姆·汉克斯/罗宾·怀特/加里·西尼斯/麦凯尔泰·威廉逊",
"area": "美国",
"desc": "阿甘(汤姆·汉克斯 饰)于二战结束后不久出生在美国南方阿拉巴马州一个闭塞的小镇,他先天弱智,智商只有75,然而他的妈妈是一个性格坚强的女性,她常常鼓励阿甘“傻人有傻福”,要他自强不息。 阿甘像普通孩子一样上学,并且认识了一生的朋友和至爱珍妮(罗宾·莱特·潘 饰),在珍妮 和妈妈的爱护下,阿甘凭着上帝赐予的“飞毛腿”开始了一生不停的奔跑。 阿甘成为橄榄球巨星、越战英雄、乒乓球外交使者、亿万富翁,但是,他始终忘不了珍妮,几次匆匆的相聚和离别,更是加深了阿甘的思念。 有一天,阿甘收到珍妮的信,他们终于又要见面……",
"years": "1994",
"sources": [{
"Name": "咪咕视频",
"Url": "https://m.miguvideo.com/mgs/msite/prd/detail.html?cid=714205994&pwId=d01197d3076b4164af82983c408bb996"
},
{
"Name": "爱奇艺视频",
"Url": "http://www.iqiyi.com/v_19rrk3u264.html?vfm=m_331_dbdy&fv=4904d94982104144a1548dd9040df241"
},
{
"Name": "芒果TV",
"Url": "http://www.mgtv.com/b/1068/742467.html?cxid=vb4rv4jhk"
},
{
"Name": "优酷视频",
"Url": "http://v.youku.com/v_show/id_XMTMzMDI2NjUzNg==.html?tpa=dW5pb25faWQ9MzAwMDA4XzEwMDAwMl8wMl8wMQ&refer=esfhz_operation.xuka.xj_00003036_000000_FNZfau_19010900"
},
{
"Name": "腾讯视频",
"Url": "http://v.qq.com/x/cover/r6hc2kqgvnmiejn.html?ptag=douban.movie"
},
{
"Name": "哔哩哔哩",
"Url": "https://m.bilibili.com/bangumi/play/ss25568?bsource=doubanh5"
}
],
"imgUrl": "http://s9k8pe75c.hd-bkt.clouddn.com/p2372307693.webp?e=1709114454&token=VVKWxI7zpGcuO5gCjDZAfdmZMPQ4jOj_09JHkB_S:gb2r6v05gM8ZtNMXidj1js-qvOw=",
"cateName": "电影",
"catId": 0
},
{
"episodes_info": "",
"rate": "9.1",
"cover_x": 1080,
"title": "寻梦环游记",
"playable": true,
"id": "20495023",
"cover_y": 1512,
"is_new": false,
"director": "李·昂克里奇",
"actor": "安东尼·冈萨雷斯/盖尔·加西亚·贝纳尔/本杰明·布拉特/阿兰娜·乌巴赫",
"area": "美国",
"desc": "热爱音乐的米格尔(安东尼·冈萨雷兹 Anthony Gonzalez 配音)不幸地出生在一个视音乐为洪水猛兽的大家庭之中,一家人只盼着米格尔快快长大,好继承家里传承了数代的制鞋产业。一年一度的亡灵节即将来临,每逢这一天,去世的亲人们的魂魄便可凭借着摆在祭坛上的照片返回现世和生者团圆。 在一场意外中,米格尔竟然穿越到了亡灵国度之中,在太阳升起之前,他必须得到一位亲人的祝福,否则就将会永远地留在这个世界里。米格尔决定去寻找已故的歌神德拉库斯(本杰明·布拉特 Benjamin Bratt 配音),因为他很有可能就是自己的祖父。途中,米格尔邂逅了落魄乐手埃克托(盖尔·加西亚·贝纳尔 Gael García Bernal 配音),也渐渐发现了德拉库斯隐藏已久的秘密。",
"years": "2017",
"sources": [{
"Name": "咪咕视频",
"Url": "https://m.miguvideo.com/mgs/msite/prd/detail.html?cid=701225583&pwId=d01197d3076b4164af82983c408bb996"
},
{
"Name": "腾讯视频",
"Url": "http://v.qq.com/x/cover/vjrvzv3s517g6m8.html?ptag=douban.movie"
},
{
"Name": "芒果TV",
"Url": "http://www.mgtv.com/b/322078/4265048.html?cxid=vb4rv4jhk"
}
],
"imgUrl": "http://s9k8pe75c.hd-bkt.clouddn.com/p2505426431.webp?e=1709114514&token=VVKWxI7zpGcuO5gCjDZAfdmZMPQ4jOj_09JHkB_S:-LE0Mbitb6CyLHaQieV5ixjTNyY=",
"cateName": "电影",
"catId": 0
},
{
"episodes_info": "",
"rate": "9.4",
"cover_x": 658,
"title": "这个杀手不太冷",
"playable": true,
"id": "1295644",
"cover_y": 980,
"is_new": false,
"director": "吕克·贝松",
"actor": "让·雷诺/娜塔莉·波特曼/加里·奥德曼/丹尼·爱罗",
"area": "法国 / 美国",
"desc": "里昂(让·雷诺饰)是名孤独的职业杀手,受人雇佣。一天,邻居家小姑娘马蒂尔达(纳塔丽·波特曼饰)敲开他的房门,要求在他那里暂避杀身之祸。原来邻居家的主人是警方缉毒组的眼线,只因贪污了一小包毒品而遭恶警(加里·奥德曼饰)杀害全家的惩罚。马蒂尔达得到里昂的留救,幸免于难,并留在里昂那里。里昂教小女孩使枪,她教里昂法文,两人关系日趋亲密,相处融洽。 女孩想着去报仇,反倒被抓,里昂及时赶到,将女孩救回。混杂着哀怨情仇的正邪之战渐次升级,更大的冲突在所难免……",
"years": "1994",
"sources": [{
"Name": "爱奇艺视频",
"Url": "http://www.iqiyi.com/v_19rrho32zk.html?vfm=m_331_dbdy&fv=4904d94982104144a1548dd9040df241"
}],
"imgUrl": "http://s9k8pe75c.hd-bkt.clouddn.com/p511118051.webp?e=1709114551&token=VVKWxI7zpGcuO5gCjDZAfdmZMPQ4jOj_09JHkB_S:jarvRtWWSE9sMibl-iupHx7uGsM=",
"cateName": "电影",
"catId": 0
},
{
"episodes_info": "",
"rate": "9.4",
"cover_x": 997,
"title": "楚门的世界",
"playable": true,
"id": "1292064",
"cover_y": 1500,
"is_new": false,
"director": "彼得·威尔",
"actor": "金·凯瑞/劳拉·琳妮/艾德·哈里斯/诺亚·艾默里奇",
"area": "美国",
"desc": "楚门(金•凯瑞 Jim Carrey 饰)是一个平凡得不能再平凡的人,除了一些有些稀奇的经历之外——初恋女友突然失踪、溺水身亡的父亲忽然似乎又出现在眼前,他和绝大多数30多岁的美国男人绝无异样。这令他倍感失落。他也曾试过离开自己生活了多年的地方,但总因种种理由而不能成行。 直到有一天,他忽然发觉自己似乎一直在被人跟踪,无论他走到哪里,干什么事情。这种感觉愈来愈强烈。楚门决定不惜一切代价逃离这个他生活了30多年的地方,去寻找他的初恋女友。 但他却发现自己怎样也逃不出去。真相其实很残忍。",
"years": "1998",
"sources": [{
"Name": "咪咕视频",
"Url": "https://m.miguvideo.com/mgs/msite/prd/detail.html?cid=714209619&pwId=d01197d3076b4164af82983c408bb996"
},
{
"Name": "爱奇艺视频",
"Url": "http://www.iqiyi.com/v_19rrk3u9wg.html?vfm=m_331_dbdy&fv=4904d94982104144a1548dd9040df241"
},
{
"Name": "优酷视频",
"Url": "http://v.youku.com/v_show/id_XMTMyMzc3NDQwNA==.html?tpa=dW5pb25faWQ9MzAwMDA4XzEwMDAwMl8wMl8wMQ&refer=esfhz_operation.xuka.xj_00003036_000000_FNZfau_19010900"
},
{
"Name": "腾讯视频",
"Url": "http://v.qq.com/x/cover/31082i4u5ovkrl0.html?ptag=douban.movie"
},
{
"Name": "哔哩哔哩",
"Url": "https://www.bilibili.com/bangumi/play/ss25812?bsource=douban"
}
],
"imgUrl": "http://s9k8pe75c.hd-bkt.clouddn.com/p479682972.webp?e=1709114595&token=VVKWxI7zpGcuO5gCjDZAfdmZMPQ4jOj_09JHkB_S:9xRjW3drXRyGDQVAOXIc3akt260=",
"cateName": "电影",
"catId": 0
},
]
export default list;
3.请假小程序
<template>
<view class="leave-list">
<view class="search-bar">
<input type="text" placeholder="请输入搜索内容" />
<button>一键清空</button>
</view>
<view class="list">
<view class="item" v-for="(item,index) in LeaveList" :key="index">
<view class="top">
<view class="left">
{{item.createTime}} {{item.name}}
</view>
<view class="right">
<uni-icons type="compose" size="24" color="#00aaff"></uni-icons>
<uni-icons type="trash" size="24" color="#ff0000" @tap="toDelete(item._id)"></uni-icons>
</view>
</view>
<view class="reason">
{{item.reason}}
</view>
<view class="attachment">
<view class="title">
附件
</view>
<image v-for="(img,index) in item.imgs" :src="img" mode=""></image>
</view>
<view class="time">
时间:{{item.startTime}}至{{item.endTime}}
</view>
<view class="refuse" v-if="item.status==2">
<view class="title">
驳回理由
</view>
<view>
{{item.refuseReason}}
</view>
</view>
<view class="status primary-status" v-if="item.status==0">
待审批
</view>
<view class="status success-status" v-else-if="item.status==1">
通过
</view>
<view class="status error-status" v-else="item.status==2">
不通过
</view>
</view>
</view>
<view class="add">
<navigator url="/pages/leave-application/leave-application">+</navigator>
</view>
</view>
</template>
<script>
export default {
data() {
return {
LeaveList:[]
}
},
onLoad() {
this.getLeaveList();
},
methods: {
toDelete(id){
uni.showModal({
title:"确定要删除假条?",
success: (res) => {
if(res.confirm){
uniCloud.callFunction({
name:"delete-leave",
data:{
id:id
},
success: (res) => {
console.log(res);
if(res.result.code==200){
uni.showToast({
title:"删除成功"
})
this.getLeaveList()
}
}
})
}
}
})
},
getLeaveList(){
uniCloud.callFunction({
name:"get-leave-list1",
data:{
name:uni.getStorageSync("user").name
},
success: (res) => {
console.log(res);
this.LeaveList=res.result.leaveList.data;
}
})
}
}
}
</script>
<style scoped lang="scss">
.leave-list{
background-color: #f8f8f8;
// padding: 15px;
.search-bar{
display: flex;
border-bottom: 1px solid gray;
padding:15px;
input{
border: 1px solid gray;
background-color: white;
border-radius: 5px;
height: 35px;
flex: 1;
margin-right: 8px;
padding-left: 5px;
}
button{
background-color: red;
color: white;
height: 35px;
line-height: 35px;
width: 70px;
padding: 0;
font-size: 24rpx;
}
}
.list{
padding: 15px;
.item{
background-color: white;
border-radius: 10px;
padding: 10px;
margin-bottom: 15px;
position: relative;
.top{
display: flex;
justify-content: space-between;
.left{
font-size: 34rpx;
font-weight: bold;
}
}
.reason{
color: #999;
margin: 10px 0;
}
.attachment{
.title{
color: #999;
margin-bottom: 6px;
}
image{
width: 150rpx;
height: 150rpx;
}
}
.status{
position: absolute;
bottom: 20px;
right: 10px;
background-color: #00aaff;
color: white;
width: 120rpx;
text-align: center;
padding: 5px 0;
transform: rotate(-45deg);
}
.primary-status{
background-color: #55aa00;
}
.error-status{
background-color: #ff0000;
}
}
}
.add{
position: fixed;
right: 15px;
bottom: 25px;
width: 60px;
height: 60px;
font-size: 80rpx;
color: white;
text-align: center;
border-radius: 50%;
background-color: #00aaff;
}
}
</style>
主页效果图:
登录页:
<template>
<view class="login">
<view class="title">
<view>Hello</view>
<view>欢迎登录请假管理系统</view>
</view>
<view class="form">
<input type="text" v-model="username" placeholder="请输入账号"/>
<input type="text" v-model="password" placeholder="请输入密码"/>
</view>
<view class="btn">
<button @tap="login">立即登录</button>
<view class="tip">
没有账号,请先注册
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
username:"",
password:""
}
},
methods: {
login(){
uniCloud.callFunction({
name:"login",
data:{
username:this.username,
password:this.password
},
success: (res) => {
console.log(res);
//如何拿到当前登录账号的名字,并传入获取请假列表的接口中,查找指定条件的数据
//方式一 通过路径传参 ?name=...
//方式二 把用户信息存储到本地 同步
uni.setStorageSync("user",res.result.user)
if(res.result.code==200){
uni.showToast({
title:"登录成功",
})
//延时器setTimeout
setTimeout(()=>{
uni.navigateTo({
url:"/pages/index/index"
})
},1000)
}else{
uni.showToast({
title:res.result.msg,
icon:"none"
})
}
}
})
}
}
}
</script>
<style lang="scss">
.login{
background: url("../../static/login-bg.png");
background-size: 100% 100%;
height: 100vh;
padding: 100rpx 40rpx 0;
.title{
font-size: 42rpx;
font-weight: bold;
margin-bottom: 100rpx;
}
.form{
margin-bottom: 120rpx;
input{
border-bottom: 1px solid #dddddd;
margin-bottom: 30rpx;
}
}
.btn{
button{
background-color: #3ba662;
color: white;
}
.tip{
text-align: right;
margin-top: 20rpx;
color: #cdcdcd;
}
}
}
</style>
效果图:
申请页:
<template>
<!-- <view class="leave-add">
<view class="user-info">
<view>
<text>
<span>申述人:</span>
周杰伦
</text>
</view>
<view>
<text>
<span>班级:</span>
计算机应用技术外包1班
</text>
</view>
</view>
<view class="upload-img">
<view class="title">
上传图片
</view>
<view class="upload">
<uni-file-picker
v-model="imageValue"
file-mediatype="image"
mode="grid"
file-extname="png,jpg"
:limit="1"
@progress="progress"
@success="success"
@fail="fail"
@select="select"
/>
</view>
<view class="tip">
最多可上传三张图片
</view>
</view>
<view class="reason">
<view class="uni-form-item uni-column">
<view class="title">申请理由</view>
<textarea
class="custom-textarea"
placeholder="请请输入申请理由"
></textarea>
</view>
</view>
<view class="time1">
<view class="left">
开始时间
</view>
<view class="right">
2024-05-03
</view>
</view>
<view class="time2">
<view class="left">
结束时间
</view>
<view class="right">
2024-05-03
</view>
</view>
<view class="qr">
<button @click="buttonClick" style="background-color: blue; color: white;" >确认提交</button>
</view>
</view> -->
<view class="add-leave">
<view class="stu-info">
<view>
<text>申述人:</text>
<text>{{user.name}}</text>
</view>
<view>
<text>班级:</text>
<text>{{user.stuClass}}</text>
</view>
</view>
<view class="attachment">
<view class="title">
上传图片
</view>
<uni-file-picker limit="3" :auto-upload="false" @select="onSelect"></uni-file-picker>
<view class="tip">
最多可上传三张图片
</view>
</view>
<view class="reason">
<view class="title">
申请理由
</view>
<textarea placeholder="请输入申请理由"></textarea>
</view>
<view class="time">
<view class="left">
开始时间
</view>
<view class="right">
<picker mode="date" :value="date" @change="bindStartDate">
<view class="uni-input">{{startTime}}</view>
</picker>
</view>
</view>
<view class="time">
<view class="left">
结束时间
</view>
<view class="right">
<picker mode="date" :value="date" @change="bindEndDate">
<view class="uni-input">{{endTime}}</view>
</picker>
</view>
</view>
<view class="qr">
<button @tap="addLeave" style="background-color: blue; color: white;" >确认提交</button>
</view>
</view>
</template>
<script>
export default {
data() {
const currentDate=this.getDate({
format:true
})
return {
// imageValue:[]
date:currentDate,
//开始日期
startTime:currentDate,
//结束日期
endTime:currentDate,
imgs:[],
reason:"",
user:null
}
},
onShow() {
this.user=uni.getStorageSync("user")
},
methods: {
onSelect(e){
uniCloud.uploadFile({
filePath:e.tempFilePaths[0],
cloudPath:"class1/"+Date.now()+e.tempFiles[0].name,
cloudPathAsRealPath:true,
success: (res) => {
console.log(res)
this.imgs.push(res.fileID);
}
})
},
bindStartDate:function(e) {
//把选择好日期进行复制
this.startTime=e.detail.value
},
bindEndDate:function(e) {
this.endTime=e.detail.value
},
getDate(type) {
const date = new Date();
let year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
if (type === 'start') {
year = year - 60;
} else if (type === 'end') {
year = year + 2;
}
month = month > 9 ? month : '0' + month;
day = day > 9 ? day : '0' + day;
return `${year}-${month}-${day}`;
},
addLeave(){
uniCloud.callFunction({
name:"add-leave",
data:{
name:uni.getStorageSync("user").name,
stuClass:uni.getStorageSync("user").stuClass,
imgs:this.imgs,
reason:this.reason,
startTime:this.startTime,
endTime:this.endTime,
createTime:this.createTime,
},
success: (res) => {
console.log(res);
if(res.result.code==200){
uni.showToast({
title:"假条新增成功",
icon:"success"
})
uni.navigateBack();
}
}
})
}
}
}
</script>
<style scoped lang="scss">
// .leave-add{
// background-color: #f8f8f8;
// .user-info{
// padding: 15px;
// span{
// font-weight: bold;
// }
// }
// .upload-img{
// padding: 15px;
// .title{
// font-weight: bold;
// }
// .upload{
// background-color: white;
// }
// }
// .tip{
// color: gray;
// font-size: 12px;
// }
// .reason{
// padding: 15px;
// .title{
// font-weight: bold;
// }
// .custom-textarea{
// padding: 15px;
// background-color: white;
// height: 150px;
// }
// }
// .time1{
// padding: 15px;
// background-color: white;
// position: relative;
// border: 1px;
// .left{
// padding: 5px;
// position: absolute;
// left: 0;
// top: 0;
// }
// .right{
// padding: 5px;
// position: absolute;
// right: 0;
// top: 0;
// }
// }
// .time2{
// padding: 15px;
// background-color: white;
// position: relative;
// border: 1px;
// .left{
// padding: 5px;
// position: absolute;
// left: 0;
// top: 0;
// }
// .right{
// padding: 5px;
// position: absolute;
// right: 0;
// top: 0;
// }
// }
// .qr{
// padding: 15px;
// }
// }
.add-leave{
padding: 15px;
background-color: #f8f8f8;
.stu-info{
view{
margin-top: 2px;
text:first-child{
font-weight: bold;
font-size: 34rpx;
color: #3e515c;
}
text:last-child{
color: #3e515c;
}
}
}
.attachment{
margin-top: 10px;
.title{
font-weight: bold;
font-size: 34rpx;
color: #3e515c;
}
/deep/ .file-picker__box-content{
background-color: white;
}
.tip{
font-size: 28rpx;
color: gray;
}
}
.reason{
margin-top: 10px;
.title{
font-weight: bold;
font-size: 34rpx;
color: #3e515c;
margin-bottom: 8px;
}
textarea{
background: white;
padding: 15px;
width: 92%;
}
}
.time{
display: flex;
justify-content: space-between;
background-color: white;
margin-top: 15px;
padding: 20px 15px;
.left{}
.right{}
}
.qr{
padding: 15px;
}
}
</style>
效果图:
后端需要阿里云平台连接数据,这里就不做展示,以上就是我个人练手的小程序。
通过不断的学习和实践,我逐渐掌握了uniapp的开发技巧。例如,如何合理地利用条件编译来实现不同平台下的差异化开发;如何借助第三方插件来扩展功能;如何优化性能以提升用户体验等。这些技巧不仅提升了我的开发能力,也使我更加深入地理解了uniapp的精髓。
此外,我还学会了如何调试和发布uniapp应用。调试是开发过程中必不可少的一环,通过调试,我们可以发现并解决问题,确保应用的稳定运行。而发布则是将我们的应用推向市场的重要步骤,通过了解不同平台的发布流程和要求,我们可以确保应用的顺利上线。
回顾学习过程,我认为要想学好uniapp,需要掌握扎实的Vue.js基础,了解前端开发的基本原理和技术。同时,还需要具备良好的学习能力和解决问题的能力,以便在遇到问题时能够迅速找到解决方案。
展望未来,我将继续深入学习uniapp的相关知识,探索更多的开发技巧和最佳实践。同时,我也将关注uniapp的发展动态,及时跟进新的功能和优化,以保持自己的技术水平与时俱进。
总之,学习uniapp是一次充满挑战和收获的旅程。通过不断的学习和实践,我不仅提升了自己的技能水平,也对前端开发有了更深刻的理解。我相信,在未来的开发中,我会更加熟练地运用uniapp,为用户创造出更加优秀的应用体验。