实验2 [小程序组件应用]-仿豆瓣

  • 实验目的
  1. 掌握小程序基础组件使用;
  2. 掌握小程序基本开发,能够实现仿豆瓣电影项目的开发;
  • 实验准备与环境
  1. PC
  2. Windows操作系统
  3. 微信开发者工具
  • 实验要求
  1. 学习如何应用小程序基础组件设计开发仿豆瓣电影项目;
  • 实验步骤

功能要求:设计一款模拟“豆瓣电影”的小程序,要求能够实现底部Tab切换效果、海报轮播效果、列表方式布局、电影详情页面布局等功能。

完整代码实现(包含代码和运行截图)

Index.wxll
<wxs src="../../utils/tool.wxs" module="tool"></wxs>
<view class="box">
  <!-- 静态轮播图 -->
  <view class="banner">
    <swiper indicator-dots indicator-color="rgba(255,255,255,0.5)" indicator-active-color="#fff" circular autoplay interval="4000">
      <swiper-item>
        <image src="/images/images/1.jpg"></image>
      </swiper-item>
      <swiper-item>
        <image src="/images/images/2.jpg"></image>
      </swiper-item>
      <swiper-item>
        <image src="/images/images/3.jpg"></image>
      </swiper-item>
      <swiper-item>
        <image src="/images/images/4.jpg"></image>
      </swiper-item>
    </swiper>
  </view>

  <!-- 今日热映 -->
  <view>
  <h3 class="hotscreening1">今日热映</h3>
  </view>
<!-- 电影列表 -->
  <view class="bigbox">
    <view class="section" wx:for="{{movies}}" wx:key="id">
      <view class="top" bind:tap="goMovieDetail" data-id="{{item.id}}">
        <image class="movieImg" src="{{item.img}}"></image>
      </view>
      <view class="bottom">
        <text class="moveTitle">{{item.nm}}</text>
        <view class="star-rating">
          <!-- 显示电影评分的星星 -->
          <block wx:for="{{tool.convertToStarsArray(item.sc)}}" wx:key="index">
            <image src="/images/images/stars.png" class="star" />
          </block>
          <!-- 显示电影评分 -->
          <text class="movie-score">{{item.sc}}</text>
        </view>
      </view>
    </view>
  </view>
</view>
Index.js
Page({
  data: {
    movies:[]
  },
  onReady() {
    let that = this;
    wx.request({
      url: 'https://m.maoyan.com/ajax/movieOnInfoList', 
      success (res) {
        that.setData({movies:res.data.movieList})
        
      }
    })
  },
  goMovieDetail(e) {
    let id = e.currentTarget.dataset.id;
    wx.navigateTo({
      url: '/pages/moviedetail/moviedetail?id=' + id,
    })
  }
})

Index.wxss
/* 主页整体样式 */
.box{
  padding: 10px;
}
/* 轮播图样式 */
.banner{
  width: 100%;
  height: 140rpx;
  border-radius: 20rpx;
}
.banner swiper{
  height: 120rpx;
  width: 100%;
}
.banner image{
  width: 100%;
  height:50px;
  border-top-left-radius: 10rpx;
  border-top-right-radius: 10rpx;
}
/* 标题样式 */
.hotscreening1{
  margin-top: 5rpx;
  font-weight: bold;
  font-size: 50rpx;

}
/* 
电影方框样式 */

image{
  width: 100%;
  height:50px;
  /* border-radius: 10rpx; */
  border-top-left-radius: 10rpx;
  border-top-right-radius: 10rpx;
}

.title{
  display: block;
  margin: 18rpx 0;
  font-size: 15pt;
  font-weight: 500
  
}
.bigbox{
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: space-between;
}
.section{
  flex: 0 0 31.3%;
  border-radius: 10rpx;
  box-sizing: border-box;
  margin-right:3rpx;
  margin-bottom:18rpx;
  padding-top:10rpx;
  text-align: center;
  padding-top: 0;
  box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px;
  background-color: white;
}
.section:nth-child(3n+3){
  margin-right:0;
}
.bottom{
  padding-bottom: 10rpx;
  padding-left: 6rpx;
  padding-right: 6rpx;
  box-sizing: border-box;
  
}
.movieImg{
  height: 300rpx;
}
.moveTitle{
  font-size: 10pt;
  overflow: hidden;
  font-weight: 700;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 1; /*3表示只显示3行*/
  -webkit-box-orient: vertical;
}
/* 五星样式开始 */
.star-rating {
  display: flex; /* 使用Flex布局 */
  align-items: center; /* 垂直居中 */
  justify-content: center; /* 从行首开始排列 */
  vertical-align: middle;
}
.star {
 margin-right: 5rpx;
  width: 12px; /* 调整为需要的尺寸 */
  height: 12px; /* 调整为需要的尺寸 */
  display: inline-block; /* 确保图标按行内块级元素显示 */
}
.movie-score {
  margin-left: 6rpx; /* 评分文字与星星图标的间隔 */
  font-size:10pt;
  color: #666; /* 可以根据需要调整颜色 */
  
}
/* 五星样式结束 */


Moviesdeail.wxml
<wxs src="../../utils/tool.wxs" module="tool"></wxs>
<view class="main">
  <!-- 头部 -->
  <view class="bannerTop">
    <view class="left">
      <image src="{{movieDetail.img}}" mode="widthFix" class="mimg" />
    </view>
    <view class="right">
      <view class="top">
        <text class="mName">{{movieDetail.nm}}</text>
        <text class="engName">{{movieDetail.enm}}</text>
      </view>
      <view class="middle">
        <text class="mSubject">{{movieDetail.typeDesc}}/{{movieDetail.cat}}</text>
        <text class="locatimes">{{movieDetail.src}}/片长{{movieDetail.dur}}分钟</text>
        <text class="stars">{{movieDetail.star}}</text>
        <!-- 显示电影评分的星星 -->
        <view class="star-rating ">
          <block wx:for="{{tool.convertToStarsArray(movieDetail.sc)}}" wx:key="index">
            <image src="/pages/images/Start/{{item}}.png" class="star" />
          </block>
          <!-- 显示电影评分 -->
          <text class="movie-score">{{movieDetail.sc}} 分</text>
        </view>
      </view>
      <view class="bottom">
        <text class="releaseDate">{{movieDetail.pubDesc}}</text>
      </view>
    </view>
  </view>
  <!-- 简介 -->
  <!-- 提供文字展开功能 -->
  <view class="bannerCenter">
    <h3>简介</h3>
    <view class="contentInner showArea {{!onFold ? 'text-clamp' + 2 : ''}}" bindtap="{{foldable ? 'handleFold' : ''}}" id="show">
      {{movieDetail.dra || "示例文本"}}
    </view>
    <view class="contentInner hideArea" id="hide">{{movieDetail.dra || "示例文本"}}</view>
    <view class="foldInner flex-end" wx:if="{{showFold}}">
      <text class="fold" catchtap="handleFold">{{onFold ? "收起" : "展开"}}</text>
    </view>
  </view>
  <!-- 演示剧照 -->
  <view class="bannerSection1">
    <h3>剧照</h3>
    <view class="scroll">
      <view class="page-section">
        <view class="page-section-spacing">
          <scroll-view class="scroll-view_H" scroll-x="true" style="width: 100%">
            <view class="scroll-view-item_H " wx:for="{{movieDetail.photos}}" wx:key="index">
              <image src="{{item}}" mode="heightFix" class="stagePhoto" bindtap="photoView" data-image="{{item}}"></image>
            </view>
          </scroll-view>
        </view>
      </view>
    </view>
    <view>
    </view>
  </view>
  <!-- 预告片 -->
  <view class="video-section">
    <h3>预告片</h3>
  </view>
  <video id="myVideo" src="{{videoSrc}}" show-center-play-btn='{{true}}' show-play-btn="{{true}}" controls style="width: 100%;"></video>
</view>
Moviesdeail.js
// pages/detail/detail.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    id: "",
    movieDetail: {},
    previewImage: [],
    onFold: false,
    showFold: false,
    onReady: false,
    foldable: true,
    videoSrc: "",
    mtitle: ""
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    this.setData({
      id: options.id
    });
    setTimeout(() => {
      this.getMovieDetail();
    }, 500)
  },
  photoView(e) {
    console.log(e)
    const photos = e.currentTarget.dataset.image;
    wx.previewImage({
      current: 'photos', // 当前显示图片的http链接
      success(res) {
        console.log("ok")
      }
    })
  },
  //获取电影信息
  getMovieDetail() {
    let that = this;
    wx.request({
      url: 'https://m.maoyan.com/ajax/detailmovie?movieId=' + this.data.id,
      header: {
        'content-type': 'application/json' // 默认值
      },
      success(res) {
        console.log(res.data.detailMovie);
        that.setData({
          movieDetail: res.data.detailMovie,
          previewImage: res.data.detailMovie.photos,
          videoSrc: res.data.detailMovie.vd,
        })
        wx.setNavigationBarTitle({
          title: res.data.detailMovie.nm
        });
      }
    })
  },
  //点击图片预览
  photoView(e) {
    let that = this;
    let image = e.currentTarget.dataset.image
    wx.previewImage({
      current: image, // 当前显示图片的http链接
      urls: that.data.previewImage // 需要预览的图片http链接列表
    })
  },
  // 展开折叠按钮
  handleFold() {
    this.setData({
      onFold: !this.data.onFold
    })
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {
    this.data.onReady = false;
  },
  // 获取高度,用于显示展开折叠 两个文字
  getHeight(){
    const query = wx.createSelectorQuery().in(this);
    query.selectAll(".showArea,.hideArea").boundingClientRect(res => {
      this.setData({
        showFold: res[0].height < res[1].height
      })
      console.log(res)
    }).exec()
  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow() {
    setTimeout(()=>{
      this.getHeight();
    },800)
  }
})
Moviedeail.wwxss
page{
  background-color: #14a720e0;
  color: aliceblue;
  padding-bottom: 20rpx;
}

.main {
  padding: 30rpx;
}

.bannerTop {
  display: flex;
  box-sizing: border-box;
  position: relative;

}

.bannerSection1{
  margin-top: 15rpx;
  margin-bottom: 15rpx;
}
.video-section{
  margin-bottom: 20rpx;
}

.bannerTop>view {
  flex: 0 0 60%;
}

.mimg {
  width: 100%;

  border-radius: 10rpx;
  
}

.bannerTop>.left {
  flex: 1;

}

.bannerTop>.right {
  margin-left: 20rpx;
  display: flex;
  flex-direction: column;
  align-content: space-around;
  justify-content: space-evenly;
  
}

.bannerTop>.right text {
  display: block;
}

.mName {
  font-size: 13pt;
  font-weight: 700;
  color: aliceblue;

}

.right>.top {

  /* justify-content: space-evenly; */
  color: rgb(255, 255, 255);
  font-size: 9pt;
  font-weight: 500;
  line-height: 1.5;
}

.engName {
  font-size: 11pt;
  font-weight: 600;
}

h3 {
  line-height: 2.2;
  font-weight: 700;
  font-size: 14pt;
}
.mSubject,.locatimes{
  font-size: 10pt;
}
.releaseDate{
  font-size: 10pt;

}

.stars{
  font-size: 11pt;

}


/* 文字省略展开 */
.contentInner {
  width: 690rpx;
  color: #ffffff;
  font-size: 30rpx;
  line-height: 1.35;
  text-align: justify;
  box-sizing: border-box;
}
.hideArea {
  box-sizing: border-box;
  display: -webkit-box;
  overflow: hidden;
  position: fixed;

  top: 100vh;
  left: -100vw;
}
.foldInner {
  width: 690rpx;
  padding-top: 10rpx;
  transition: 1s all;
}
.foldInner .fold {
  color: #ffffff;
  font-size: 32rpx;
  cursor: pointer;
}
.text-clamp2 {
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;

}
.flex-end {

  display: -webkit-box;
  display: -webkit-flex;
  display: flex;
  justify-content: flex-end;
  -webkit-justify-content: flex-end;
}

/* 滚动条 */

.scroll-view_H{
  white-space: nowrap;
}

.scroll-view-item_H{
  display: inline-block;
  padding: 10rpx;
  box-sizing: border-box;
  /* width: 100%; */
}
.stagePhoto{
  height: 300rpx;
}


/* 五星样式开始 */

/* 五星样式开始 */
.star-rating {
  display: flex; /* 使用Flex布局 */
  align-items: center; /* 垂直居中 */
  justify-content: flex-start; /* 从行首开始排列 */
  vertical-align: middle;
  /* margin-bottom: 15rpx;
  margin-top: 15rpx; */
}

.star {
 
 margin-right: 5rpx;
  width: 15px; /* 调整为需要的尺寸 */
  height: 15px; /* 调整为需要的尺寸 */
  display: inline-block; /* 确保图标按行内块级元素显示 */
}

.movie-score {
  margin-left: 5rpx; /* 评分文字与星星图标的间隔 */
  font-size: 10pt;
  color: rgb(255, 255, 255); /* 可以根据需要调整颜色 */
  
}

/* 五星样式结束 */


Search.wxml
<view class="containers">
  <view class="searchBox">
    <view class="search-container">
      <input class="search-input" type="text" placeholder="请输入您要搜索的电影" model:value="{{searchKey}}" bindconfirm="searchMovie"  />
      <button class="search-btn" bindtap="searchMovie">搜索</button>
    </view>
    <view class="searchHistory" wx:if="{{searchList.length==0}}">
      <view class="title">暂时没有搜索记录</view>
    </view>
  </view>
  <view class="cons" wx:if="{{searchList.length>0}}">
    <view >
      <view class="tops">
        <view class="title">搜索历史</view>
        <view bind:tap="clearHistory" class="clear">清空历史</view>
      </view>
      <view class="bottoms">
        <block wx:for="{{searchList}}" wx:key="index">
          <view class="c_item" data-index="{{index}}" bindlongpress="deleteSearchOne" bind:tap="getSearchOne">{{item}}</view>
        </block>
      </view>
    </view>
  </view>
</view>
Search.js

Page({

  data: {
    searchKey: "",
    searchList: [],
    movieList:[]
  },
 
  onLoad(options) {

  },
  onReady() {
    if (wx.getStorageSync('search_history')) {
      console.log(JSON.parse(wx.getStorageSync('search_history')));
      this.setData({
        searchList: JSON.parse(wx.getStorageSync('search_history'))
      })
    } else {
      wx.setStorageSync('search_history', JSON.stringify(this.data.searchList))
    }
  },
  // 搜索按钮
  searchMovie() {
    let that = this;
    this.data.searchList.forEach((item, index) => {
      if (item == this.data.searchKey) {
        this.data.searchList.splice(index, 1);
      }
    })
    this.data.searchList.unshift(this.data.searchKey);
    this.setData({
      searchList: this.data.searchList.slice(0, 15)
    })
    wx.setStorageSync('search_history', JSON.stringify(this.data.searchList))
    that.goSearchDetail();
  },
goSearchDetail(){
  let that = this;
  wx.navigateTo({
    url: '/pages/SearchDetail/SearchDetail?searchName='+that.data.searchKey,
    success: function(res) {
      console.log("成功打开详情页")
    }
  })
},
  // 点击了搜索历史
  getSearchOne(e) {
    let {
      index
    } = e.currentTarget.dataset, {
      searchList
    } = this.data;
    let va = searchList[index]
    this.setData({
      searchKey: va
    })
    this.searchMovie()
  },
  //删除搜索历史
  deleteSearchOne(e) {
    let that = this;
    let {
      index
    } = e.currentTarget.dataset, {
      searchList
    } = this.data;
    let va = searchList[index];
    wx.showModal({
      title: '提示',
      content: '删除该记录?',
      success(res) {
        if (res.confirm) {
          that.data.searchList.forEach((item, index) => {
            if (item == va) {
              that.data.searchList.splice(index, 1);
            }
          })
          that.setData({
            searchList: that.data.searchList.slice(0, 15)
          })
          wx.setStorageSync('search_history', JSON.stringify(that.data.searchList))
        } else if (res.cancel) {
          console.log('用户点击取消')
        }
      }
    })
  },
  clearHistory() {
    console.log(111)
    this.setData({
      searchList: []
    })
    wx.removeStorageSync('search_history')
  },

})
Search.wxss
.containers{
  padding: 20rpx;
}
.search-container {
  display: flex;

}

.search-input {
  flex: 2; 
  border: 1px solid #ddd;
  padding: 5px 10px;
  border-radius: 3px;
  margin-right: 10px;
}

.search-btn {
  flex: 0.5;
  padding: 5px 10px; 
  background-color: #198aad;
  color: white;
  border: none;
  border-radius: 3px;
  white-space: nowrap; /* 防止文本换行,如果按钮文本较长的话 */
}

.searchHistory{
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  height: 80vh;
  font-size: 15pt;
  font-weight: 500;
}

image{
  width:30vw;
}

/* 搜索历史 */
.cons{
  padding: 15rpx;
  box-sizing: border-box;
  margin-top: 15rpx;
}
.tops{
  display: flex;
  justify-content: space-between;
  margin-bottom: 15rpx;
}

.bottoms{
  display: flex;
  flex-direction: row;
  margin-top: 20rpx;
}

.title{
  font-size: 13pt;
  font-weight: 600;
  color: #4e5050;
}
.clear{
  color: #999;
  font-size: 13pt;
}

.c_item{
  font-size: 12pt;
  height: 58rpx;
  line-height: 58rpx;
  padding: 0 26rpx;
  background: rgba(34, 37, 158, 0.171);
  border-radius: 31rpx;
  justify-content: center;
  margin-bottom: 24rpx;
  margin-right: 24rpx;
  white-space:pre;
  color: #999;
}
.list{
  margin-top: 40rpx;
  flex-wrap: wrap;
}

.color{
  color: #83B7FD;
}


Home.wxml
<!-- index.wxml -->

<view class="container">
  <view class="user-info">
    <image class="avatar" src="{{avatarUrl}}"></image>
    <text class="nickname">{{nickname}}</text>
  </view>

  <view>
    <text>收藏的电影</text>
    <view>
      <block wx:for="{{movies}}" wx:key="index">
        <text>{{movies.img}}</text>
      </block>
    </view>
  </view>

  <view class="section">
    <text class="section-title">观看记录</text>
    <view class="movie-list">
      <block wx:for="{{watchedMovies}}" wx:key="index">
        <text>{{item}}</text>
      </block>
    </view>
  </view>

</view>

Home.js
// 在Page({})中编写页面逻辑

Page({
  data: {
    avatarUrl: 'https://p2.music.126.net/9FhSEQtMhP-JP3_U84YfWQ==/109951165798773745.jpg?param=130y130',
    nickname: '李泉城',
    movies:[]
  },
  onReady() {
    let that = this;
    wx.request({
      url: 'https://m.maoyan.com/ajax/movieOnInfoList', 
      success (res) {
        that.setData({movies:res.data.movieList})
        
      }
    })
  }
});

Home.wxss

.container {
  padding: 20rpx;
  margin-left: 10rpx;
  display: flex; 
  flex-direction: column; 
  align-items: flex-start; 
}

.user-info {
  display: flex;
  align-items: center;
  margin-bottom: 20rpx;
  margin-left: 50rpx;
}

.avatar {
  width: 80rpx;
  height: 80rpx;
  border-radius: 50%;
  margin-right: 10rpx;
}

.nickname {
  font-size: 24rpx;
}

.section {
  margin-bottom: 20rpx;
}

.section-title {
  font-size: 20rpx;
  font-weight: bold;
  margin-bottom: 10rpx;
}

.movie-list {
  display: flex;
  flex-wrap: wrap;
}

.movie-list text {
  padding: 5rpx 10rpx;
  margin-right: 10rpx;
  margin-bottom: 10rpx;
  background-color: #f0f0f0;
  border-radius: 5rpx;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值