其四个页面,轻量级音乐播放器搭建

By admin in 4858美高梅 on 2019年4月13日

在微信支付中,写过的二个简约的音乐播放组件,记录下。

轻量级音乐播放器搭建 三

 

紧接着此前的干活,今后想要对歌曲进行呼吁。首先应该运维腾讯网云音乐的API的服务器,github地址如下。克隆这几个类型后,在终极运营:

  npm install
  node app.js

现今以此服务器就开动了,私下认可为三千端口。可是又有3个标题正是跨域,webpack未有更改默许的安插的话实际当地服务器的8080端口,可是上述的今日头条云API服务器的端口为本土服务器的2000端口,所以端口不壹样,不适合同源策略,所以那里就供给运用axios。

axios是何等?链接中是华语表达。故事在此以前尤雨溪已经济建设议接纳axios,VueResource不再举行维护。axios正是叁个依据Promise的http客户端。安装axios:

  cnpm install axios --save

上边正是在webpack的地面服务器中配置axios,回到项目标根目录中,找到dev-server.js那个文件,那几个文件便是支付环境的服务器。就在这么些文件中开始展览路由与axios请求转载的布署。

  ......
  var axios = require('axios')
  var app = express()
  ​
  var apiRoutes = express.Router()
  ​
  apiRoutes.get('/getSomething', function (req, res) {
    var url = 'https://anotherUrl.com/something'
    axios.get(url, {
      headers: {
        referer: 'https://anotherUrl.com/',
        host: 'anotherUrl.com'
      },
      params: req.query
    }).then((response) => {
      res.json(response.data)
    }).catch((e) => {
      console.log(e)
    })
  })
  ​
  app.use('/api', apiRoutes)
  ......

由上述的代码示例能够见见,使用axios步骤如下:

  1. 创制express.Router实例,用以得到路由。

  2. 对express.Router的实例进行监听各个请求,如get等。当匹配到对应的url的时候,执行回调函数。

  3. 编写回调函数,回调函数用于对请求进行转向,并取得响应。所以函数中供给转接的url,然后就足以调用axios模块的get方法(那里以用户发起get请求为例)。axios的get方法有四个参数,第2个参数便是要进行转向的url,这几个必选;第二个参数是种种配置,包含headers,这些对于跨域的伸手来说1贰分首要,因为她改动了请求底部消息;汗包罗3个参数正是params,就是请求所引导的参数。然后便是实践promise的then回调,将response的data传回res的json。

  4. 末尾,将express框架应用实例调用use方法来利用这些router实例,当呼吁的路子相称到第一个参数的路子的时候,就路由到apiRoutes那几个模块进行拍卖。

故此在dev-server.js中添加如下代码:

  // axios
  var apiRouter = express.Router()
  apiRouter.get('/getDefaultMusicList', function (req, res) {
    let url = 'http://localhost:3000/personalized/newsong'
    axios.get(url, {
      headers: {
        referer: 'http://localhost:3000/',
        host: 'localhost:3000'
      },
      params: req.query
    }).then((response) => {
      console.log(response)
      res.json(response.data)
    }).catch((err) => {
      console.log(err)
    })
  })
  app.use('/api', apiRouter)

那样的话,就能够在music-player.vue中举办歌单的呼吁。然则先不要心急,因为相比好的思绪与框架是拓展模块化,于是在src的common/api目录中创造这个请求的功用,然后在vue组件中去引入使用这个模块。所以先创建getDefaultMusicList.js文件:

  import axios from 'axios'
  export default function getDefaultMusicList () {
    return axios.get('/api/getDefaultMusicList')
      .then((res) => {
        return Promise.resolve(res.data)
      })
  }

此地便是使用了2个axios的http请求作用,地址正是地面服务器的地点加上路由的api(与事先在apiRouter实例中的路由对应),重回那些函数的乞请再次来到值。那么这几个请求得到数码未来又再2遍的开始展览辨析,将分析后的多少再次回到。今后能够在music-player.vue中使用了:

  <template>
    <div class="music-player">
      <header-bar></header-bar>
      <div class="mid">
        <img src="../../assets/logo.png">
      </div>
      <music-controller></music-controller>
    </div>
  </template>
  ​
  ​
  <script>
    import HeaderBar from 'components/header-bar/header-bar'
    import MusicController from 'components/music-controller/music-controller'
    import getDefaultMusicList from 'api/getDefaultMusicList'
  ​
    export default {
      components: {
        HeaderBar,
        MusicController
      },
      created () {
        console.log('MusicPlayer Created')
        this._getDefaultMusicList()
      },
      methods: {
        _getDefaultMusicList () {
          getDefaultMusicList().then((res) => {
              if (res.code === 200) {
                this.defaultMusicList = res.result
                console.log(this.defaultMusicList)
              }
            })
        }
      },
      data () {
        return {
          defaultMusicList: [],
        }
      }
    }
  </script>

现行反革命一经打开浏览器的控制台,就会看到眼下以此music-player组件中的defaultMusicList的多少,大家已经取获得了,是二个尺寸为十的数组。

近期要想播放1首歌曲,改如何是好吧?查询API的文书档案,找到了获得音乐
url的接口。如果将赢获得的歌单中任一id作为参数举行呼吁,在浏览器中会是之类的回到结果:

接下来呢,再次回到值中data数组只有1个目的,对象里有2个url,打开这几个url就能够听见歌曲了。然则机智的本人发现事情并不是那么粗略,歌曲的时长在哪?歌曲的背景图片在哪?歌曲的各样参数都在哪?笔者靠这一个list中的成分进行未来拾叁分复杂。种种参数都不理解是为啥的,以第一个因素为例,他的歌曲背景图片的地方是在song->album->blurPicUrl之中。至于播放时间长度,这一个近乎是在song->bMusic/hMusic/lMusic/mMusic->playtime中。那多少个music小编臆度应该是音乐品质的分别吧。可是这一个playtime怎么解释,那里的数字是1856九陆,臣妾想不通啊。总结得不到一个像是时间的结果。其它这些是在list中才有的属性,假使在其它的地点或许就从不这几个天性了。真令人头大。算了这几个先不管了,先用那个数据吧,至于播放时间就先不用了,也正是进度条暂且也不写了。

那么上面正是对歌单中的歌曲进行广播,作者想要对列表进行巡回播放。因为列表的尺寸是零星的然而不能够播放完暗中认可的列表就停下了,所以应该实行巡回的播报。所以博得完歌单之后就展开机动的广播。所以在api目录中新建3个播放歌曲的函数,播放歌曲是其它一个请求,所以照旧选用axios来开始展览转向:

因而创立playThisMusic.js文件:

  import axios from 'axios'
  ​
  export default function playThisMusic (music) {
    let response = getMusicUrl(music.id)
    //axios.get('')
  }
  ​
  function getMusicUrl(id) {
    let url = `/api/getMusicUrl/url?id=${id}`
    return axios.get(url).then((res) => {
      console.log(res.data)
      return Promise.resolve(res.data)
    })
  }

那边就是现在有叁个在defaultMusicList中的成分music。有了那些成分,能够获得部分有关这些歌曲的音信,但是获得持续歌曲播放的地点。所以采用getMusicUrl方法来博取歌曲播放的地方。那那一个url地址怎么获得呢?照旧要经过当前歌曲的id发送1个呼吁,然后再展开剖析。可是依然老难点,就是赢得url又跨域了,所以照旧要再服务器端使用axios来发送请求。

鉴于跨域发送的请求估摸会有无数,所以本人想把这一个apiRouter做成三个模块来引入到服务器端文件。所以再build目录创造apiRouter文件,并举办改动与引用如下:

  ......
  apiRouter.get('/getMusicUrl/url', function (req, res) {
    let url = `http://localhost:3000/music/url`
    axios.get(url, {
      headers: {
        referer: 'http://localhost:3000/',
        host: 'localhost:3000'
      },
      params: req.query
    }).then((response) => {
      res.json(response.data)
    }).catch((err) => {
      console.log(err)
    })
  })
  ​
  module.exports = apiRouter

此处有几许就是专注apiRouter所get的率先个url参数,参数必须求完全相称才能够,假若只写为’/getMusicUrl’则是相配不到的。url部分便是贰个呼吁的’?’从前的有的,之后为params部分。然后作为3个模块,随后应当使用module.exports来对apiRouter举办暴流露来。

当今再控制罗利就足以见到有了回去的新闻。是二个对象,对象的data部分是八个尺寸为一的数组。数组中的url属性正是大家须求的广播地址。所以回来playThisMusic.js文件一连对playThisMusic函数实行改动:

  import axios from 'axios'
  ​
  export function playThisMusic (music) {
    let url = ''
    getMusicUrl(music.id).then((res) => {
      if (res.code === 200) {
        url = res.data[0].url
      } else {
        console.log('未能获取播放地址')
      }
    })
  }
  ​
  export function getMusicUrl(id) {
    let url = `/api/getMusicUrl/url?id=${id}`
    return axios.get(url).then((res) => {
      console.log(res.data)
      return Promise.resolve(res.data)
    })
  }

自己一发轫觉得需求对那个广播的url进行呼吁才能播放音乐,结果发现不是那回事。在html5中,有特别的audio标签来播放音频文件。所以上述代码中的playThisMusic方法就不供给了。修改music-player.vue文件:

  <template>
    <div class="music-player">
      <header-bar></header-bar>
      <div class="mid">
        <audio :src="currentMusicUrl" autoplay></audio>
        <img src="../../assets/logo.png">
      </div>
      <music-controller></music-controller>
    </div>
  </template>
  ​
  ​
  <script>
    import HeaderBar from 'components/header-bar/header-bar'
    import MusicController from 'components/music-controller/music-controller'
    import getDefaultMusicList from 'api/getDefaultMusicList'
    import {getMusicUrl} from 'api/playThisMusic'
  ​
    export default {
      components: {
        HeaderBar,
        MusicController
      },
      created () {
        console.log('MusicPlayer Created')
        this._getDefaultMusicList()
      },
      methods: {
        _getDefaultMusicList () {
          getDefaultMusicList()
            .then((res) => {
              if (res.code === 200) {
                this.defaultMusicList = res.result
                console.log(this.defaultMusicList)
              }
            })
            .then(() => {
              this._playDefaultMusic(this.defaultMusicList.length - 1)
            })
        },
        _playDefaultMusic (lastIndex) {
          let currentIndex
          if (lastIndex === this.defaultMusicList.length - 1) {
            currentIndex = 0
          } else {
            currentIndex = lastIndex + 1
          }
          getMusicUrl(this.defaultMusicList[currentIndex].id)
            .then((res) => {
              this.currentMusicUrl = res.data[0].url
            })
        }
      },
      data () {
        return {
          defaultMusicList: [],
          currentMusicUrl: '',
        }
      }
    }
  </script>

怎么未有声响?小编找了半天的错误,发现原因便是慢!音频未有缓冲好,可是耐心等待壹会着实会听到断断续续地播报的,至于怎么如此慢笔者也不明了,假诺直白伸手音乐广播的url的话可以眨眼之间间开拓,可是作为audio标签的src就相当慢,作者也不亮堂是干吗。欸,不行。以往一向伸手的话平素未有歌了,小编猜或者是因为新浪云音乐那边的界定。

随着往下开始展览,以往一旦要让歌曲要自行调到下2个歌曲。经过查阅W3C文书档案,发现audio成分有这一个得力的轩然大波。

Event name Dispatched when…
loadstart The user agent begins looking for media data, as part of the resource selection algorithm.
progress The user agent is fetching media data.
suspend The user agent is intentionally not currently fetching media data, but does not have the entire media resource downloaded.
abort The user agent stops fetching the media data before it is completely downloaded, but not due to an error.
emptied A media element whose networkState was previously not in the NETWORK_EMPTY state has just switched to that state (either because of a fatal error during load that’s about to be reported, or because the load() method was invoked while the resource selection algorithm was already running).
error An error occurs while fetching the media data.
stalled The user agent is trying to fetch media data, but data is unexpectedly not forthcoming.
play Playback has begun. Fired after the play() method has returned, or when the autoplay attribute has caused playback to begin.
pause Playback has been paused. Fired after the pause() method has returned.
loadedmetadata The user agent has just determined the duration and dimensions of the media resource
loadeddata The user agent can render the media data at the current playback position for the first time.
waiting Playback has stopped because the next frame is not available, but the user agent expects that frame to become available in due course.
playing Playback has started.
canplay The user agent can resume playback of the media data, but estimates that if playback were to be started now, the media resource could not be rendered at the current playback rate up to its end without having to stop for further buffering of content.
canplaythrough The user agent estimates that if playback were to be started now, the media resource could be rendered at the current playback rate all the way to its end without having to stop for further buffering.
seeking The seeking IDL attribute changed to true and the seek operation is taking long enough that the user agent has time to fire the event.
seeked The seeking IDL attribute changed to false.
timeupdate The current playback position changed as part of normal playback or in an especially interesting way, for example discontinuously.
ended Playback has stopped because the end of the media resource was reached.
ratechange Either the defaultPlaybackRate or the playbackRate attribute has just been updated.
durationchange The duration attribute has just been updated.
volumechange Either the volume attribute or the muted attribute has changed. Fired after the relevant attribute’s setter has returned.

对此要切换歌曲,时机就在于1首歌的利落地点。所以能够利用ended事件来切换当前播报的音乐。由于要切换歌曲,绑定事件等。所以要对audio成分绑定ended事件,所接触的函数为_playDefaultMusic,然则这些函数在此以前写的急需传递贰个脚下的索引值。近期自己想有二种方案,1是在audio成分上绑定三个自定义特性index来代表索引;另3个是无须传递索引,函数改为无参数,索引值改为由data保存(早先时期修改为vuex控制索引状态)。明显无论从代码简洁、能源支配如故中期的扩展上都以第二种办法较好。

笔记内容:创设音信详情页面
笔记日期:201八-01-0玖

天涯论坛云音乐

music

音乐广播组件。

鉴于初步的时候是听第二首歌(其实第几首根本无视),所以currentMusicIndex开首化为个单列表的长度减一(那句话是后来补上的,不能起始化为length

壹,因为那个数组实际上在壹初阶的时候是向来不定义的)。然后笔者想切换播放歌曲不管是点击下一首也好,依然左右滑动也好,还是自动播放下一首也好,本质上都是对currentMusicIndex举办改动。所以能够观望currentMusicIndex这几个变量的成形,若是有变动,那么就切换能源并且播放音频。修改代码如下:

  <template>
    <div class="music-player">
      <header-bar></header-bar>
      <div class="mid">
        <audio :src="currentMusicUrl" autoplay @ended="_playDefaultMusic(currentMusicIndex)" ref="audio"></audio>
        <img src="../../assets/logo.png">
      </div>
      <music-controller></music-controller>
    </div>
  </template>
  ​
  ​
  <script>
    import HeaderBar from 'components/header-bar/header-bar'
    import MusicController from 'components/music-controller/music-controller'
    import getDefaultMusicList from 'api/getDefaultMusicList'
    import {getMusicUrl} from 'api/playThisMusic'
  ​
    export default {
      data () {
        return {
          defaultMusicList: [],
          currentMusicUrl: '',
          currentMusicIndex: 0,
        }
      },
      components: {
        HeaderBar,
        MusicController
      },
      created () {
        console.log('MusicPlayer Created')
        this._getDefaultMusicList()
      },
      methods: {
        _getDefaultMusicList () {
          getDefaultMusicList()
            .then((res) => {
              if (res.code === 200) {
                this.defaultMusicList = res.result
                console.log(this.defaultMusicList)
              }
            })
            .then(() => {
              this._playDefaultMusic()
            })
        },
        _playDefaultMusic () {
          if (this.currentMusicIndex === this.defaultMusicList.length - 1) {
            this.currentMusicIndex = 0
          } else {
            this.currentMusicIndex = this.currentMusicIndex + 1
          }
          getMusicUrl(this.defaultMusicList[this.currentMusicIndex].id)
            .then((res) => {
              this.currentMusicUrl = res.data[0].url
            })
        }
      },
      watch: {
        currentMusicIndex: function (newVal, oldVal) {
          console.log(this.$refs.audio)
          this.$refs.audio.play()
        }
      }
    }
  </script>

能够运作,可是报贰个很稀奇的荒唐:

  Uncaught (in promise) DOMException: The element has no supported sources.

缘何吧?笔者想是因为1初阶的时候audio中的src绑定的变量是currentMusicUrl,但是这么些data初步化为空字符串,可是作者那里play()方法调用的空子是在_playDefaultMusic中改变了currentMusicIndex,然后在修改的currentMusicUrl。所以会现出src未有的场所。并且还由别的bug。这一个荒唐只报二回是因为最初始的一遍直接未有src。把两段代码交换一下任务,有哪些事明日加以。太晚了,得回到。

 

 

参考链接:

  1. axios粤语表达

  2. axios
    github

  3. express
    文档

  4. 网易云API文档

  5. Promise
    介绍

  6. audio
    W3C介绍

  7. vue
    watch 文档


git地址 其四个页面,轻量级音乐播放器搭建。https://github.com/majunchang/wangYiYun-Music

属性

属性名 类型 默认值 说明
music String   传入的音乐资源地址
musicStyle String (随便写了个) 音乐组件的样式
rotate Boolean true 播放时是否有旋转效果
iconOn String (随便写了个) 音乐播放时的icon地址
iconOff String (随便写了个) 音乐暂停时的icon地址

从小说列表跳转到音信详情页(组件自定义属性及取得属性)

在编写从文章列表跳转到新闻详情页的代码从前,先来修改一下事先的页面,此前大家编辑了多少个模板文件,然而还有五个细节尚未宏观好,一个是post.wxss中的.post-container样式未有移植到模板文件中,另1个是wxml模板文件中每句数据绑定代码都亟待经过item那些子成分去调用属性,显得有个别麻烦,大家能够运用壹种语法去消除这么些题材。

一.率先将post.wxss中的.post-container样式移植到模板文件中

2.解决item重复的标题,在post.wxml中校在此以前的 template
代码修改为以下内容:

<template is="postItem" data="{{...item}}" />

4858美高梅 ,接下来模板文件中的数据绑定代码就不供给重复使用item子成分实行性能的调用了:

<!-- 模板文件需要使用template标签包围 -->
<template name="postItem">
  <view class='post-container'>
      <view class='post-author-date'>
        <image src='{{avatar}}' class='post-author'></image>
        <text class="post-date">{{date}}</text>
      </view>
      <text class='post-title'>{{title}}</text>
      <image class='post-image' src='{{imgSrc}}'></image>
      <text class='post-content'>{{content}}</text>
      <view class='post-like'>
        <image src='../..icon/chat.png' class='post-like-img'></image>
        <text class='post-like-font'>{{reading}}</text>
        <image src='../..icon/view.png' class='post-like-img'></image>
        <text class='post-like-font'>{{collection}}</text>
      </view>
    </view>
</template>

做到上述的修改后,就能够发轫工编织制音信详情页的代码了:

一.创设目录文件结构:
4858美高梅 1

贰.出于大家须要实现点击一个稿子列表中的小说就跳转到该小说的详情页面,所以我们还得给每一个篇章做多个标识符,不然哪个人知道您点的是哪篇文章。这几个标识符能够写在数据文件中,作为五日性质存在,所以需求在数据文件中为每四个篇章多少都助长一个属性,小编定义的属性名称是postId:

// 将数据整合成数组类型
var local_database = [
  {
    date: "Jan 06 2018",
    title: "正是虾肥蟹壮时",
    imgSrc: "post/crab.png",
    avatar: "vatar/1.png",
    content: "“山明水净夜来霜,数树深红出浅黄。试上高楼清入骨,岂如春色嗾人狂。”金秋时节,天高云淡,秋风送爽,气候宜人。秋风秋阳中,硕果坠挂枝头,玉米抚须含笑,高粱引颈高歌,豆荚饱满圆润。",
    reading: "112",
    collection: "96",
    postId:0,
  },
  {
    date: "Jan 03 2018",
    title: "比利·林恩的中场战事",
    imgSrc: "post/bl.png",
    avatar: "vatar/2.png",
    content: "伊拉克战争时期,来自美国德州的19岁技术兵比利·林恩(乔·阿尔文 Joe Alwyn 饰)因为一段偶然拍摄的视频而家喻户晓。那是一次规模不大却激烈非常的遭遇战,战斗中林恩所在的B班班长(范·迪塞尔 Vin Diesel 饰)遭到当地武装分子的伏击和劫持,而林恩为了营救班长不惜铤而走险冲锋陷阵。",
    reading: "92",
    collection: "65",
    postId: 1,
  },
  {
    date: "Jan 05 2018",
    title: "肖申克的救赎",
    imgSrc: "post/xs.jpg",
    avatar: "vatar/3.png",
    content: "20世纪40年代末,小有成就的青年银行家安迪(蒂姆·罗宾斯 Tim Robbins 饰)因涉嫌杀害妻子及她的情人而锒铛入狱。在这座名为肖申克的监狱内,希望似乎虚无缥缈,终身监禁的惩罚无疑注定了安迪接下来灰暗绝望的人生。",
    reading: "92",
    collection: "65",
    postId: 2,
  },
  {
    date: "Jan 01 2018",
    title: "霸王别姬",
    imgSrc: "post/bj.jpg",
    avatar: "vatar/4.png",
    content: "段小楼(张丰毅)与程蝶衣(张国荣)是一对打小一起长大的师兄弟,两人一个演生,一个饰旦,一向配合天衣无缝,尤其一出《霸王别姬》,更是誉满京城,为此,两人约定合演一辈子《霸王别姬》。但两人对戏剧与人生关系的理解有本质不同,段小楼深知戏非人生,程蝶衣则是人戏不分。",
    reading: "92",
    collection: "65",
    postId: 3,
  },
  {
    date: "Jan 08 2018",
    title: "这个杀手不太冷",
    imgSrc: "post/ss.jpg",
    avatar: "vatar/5.png",
    content: "里昂(让·雷诺饰)是名孤独的×××,受人雇佣。一天,邻居家小姑娘马蒂尔达(纳塔丽·波特曼饰)敲开他的房门,要求在他那里暂避杀身之祸。原来邻居家的主人是警方缉毒组的眼线,只因贪污了一小包×××而遭恶警(加里·奥德曼饰)杀害全家的惩罚。",
    reading: "92",
    collection: "65",
    postId: 4,
  },
  {
    date: "Jan 04 2018",
    title: "阿甘正传",
    imgSrc: "post/ag.jpg",
    avatar: "vatar/1.png",
    content: "阿甘(汤姆·汉克斯 饰)于二战结束后不久出生在美国南方阿拉巴马州一个闭塞的小镇,他先天弱智,智商只有75,然而他的妈妈是一个性格坚强的女性,她常常鼓励阿甘“傻人有傻福”,要他自强不息。",
    reading: "92",
    collection: "65",
    postId: 5,
  },
]

// 设置一个数据出口
module.exports = {
  // 输出的是一个Array对象
  postList: local_database,
}

三.在post.wxml文件中加进二个view标签,把template标签包围起来,因为template标签只是相当于叁个占位符,编写翻译之后这几个标签是不存在的。然后给那一个view标签注册二个tap事件,并且自定义二个性质进行postId的数码绑定:

<!-- 自定义属性必须以 data- 为前缀,后面连接的单词可以自定义 -->
<view catchtap="onPostTap" data-postId="{{item.postId}}">
      <template is="postItem" data="{{...item}}"/>
</view>

四.然后到post.js文件中扩大2个事件函数:

onPostTap: function(event){
    // 从事件源中获取postId数据
    var postId = event.currentTarget.dataset.postid;
    console.log("on post id is " + postId);
 },

event是事件源对象,是默许会传入的参数,currentTarget是日前被触发事件的对象对象,dataset是数据集对象,数据要从数据集对象中收获。至于怎么是因此postid获取数据而不是因此data-postId或许postId获取,请参见下图:
4858美高梅 2

如图,能够看来,自定义属性被编写翻译之后的称谓并不是原来的称谓,所以大家透过dataset数据集对象获得自定义属性的数据时索要以编写翻译后的名目为准。

五.随着就能够起来兑现页面跳转了,先在post-detail.wxml中编辑一段话:

<text>
  这是文章详情页面
</text>

然后再app.json中加上1段post-detail的消息配置,每当大家新增页面都亟待这么举办配备:

“pages/posts/post-detail/post-detail”

回去post.js中,编写页面跳转代码:

  onPostTap: function(event){
    // 从事件源中获取postId数据
    var postId = event.currentTarget.dataset.postid;
    wx.navigateTo({
      url: 'post-detail/post-detail',
    })
  },

达成上述操作编写翻译之后未来点击小说列表中的文章就可以跳转到小说详情页面了:
4858美高梅 3


连串截图

4858美高梅 4

mark

4858美高梅 5

mark

4858美高梅 6

mark

4858美高梅 7

mark

4858美高梅 8

mark

4858美高梅 9

mark

4858美高梅 10

mark

4858美高梅 11

mark

4858美高梅 12

mark

4858美高梅 13

mark

代码

properties: {
    // 音乐路径
    music: {
      type: String,
      value: '',
      observer: function (newVal) {
        this._initMusic(newVal)
      }
    },
    // 样式
    musicStyle: {
      type: String,
      value: 'position: absolute; right: 20rpx; top: 20rpx; width: 100rpx; height: 100rpx;'
    },
    // 播放时是否有旋转效果
    rotate: {
      type: Boolean,
      value: true
    },
    // 播放时的icon路径
    iconOn: {
      type: String,
      value: '/resources/img/music-on.png' // 请填写默认的图片地址
    },
    // 暂停时的icon路径
    iconOff: {
      type: String,
      value: '/resources/img/music-off.png' // 请填写默认的图片地址
    }
  }

先静后动,先构建音信详情页面样式

编写post-detail.wxml代码:

<view class='container'>
  <image src='post/sls.jpg' class='head-iamge'></image>
  <image class='audio' src='music/music-start.png'></image>
  <view class='author-date'>
    <image src='vatar/2.png' class='avatar' ></image>
    <text class='author'>zero</text>
    <text class='const-text'>发表于</text>
    <text class='date'>3天前</text>
  </view>
  <text class='title'>审美的进化机制</text>
  <view class='tool'>
    <view class='circle-img'>
      <image src='icon/collection.png'></image>
      <image class='share-img' src='icon/share.png'></image>
    </view>
    <view class='horizon'></view>
  </view>
  <text class='detail'>2017年读的书中,有一本书是《纽约时报》年度十佳(2017 Ten Best Books),即:《美的进化——达尔文被遗忘的择偶理论如何塑造动物世界乃至我们》(The Evolution of Beauty: How Darwin’s Forgotten Theory of Mate Choice Shapes the Animal World — and Us)。时报网站刊登了英文版评介的译文:如果一本科学书籍能做到有颠覆性,倡导女权主义,还能改变我们看待自己身体的方式,但同时主要还是关于鸟类的,那就是这本书了。普鲁姆是一位鸟类学家,他为达尔文的另一个基本上被忽略了的雌雄淘汰理论进行了辩护。</text>
</view>

post-detail.wxss代码:

.container {
  display: flex;
  flex-direction: column;
}

.head-iamge {
  width: 750rpx;
  height: 460rpx;
}

.author-date {
  flex-direction: row;
  margin-left: 30rpx;
  margin-top: 20rpx;
}

.avatar {
  height: 64rpx;
  width: 64rpx;
  vertical-align: middle;
}

.author {
  font-size: 30rpx;
  font-weight: 300;
  margin-left: 20rpx;
  vertical-align: middle;
  color: #666;
}

.const-text {
  font-size: 24rpx;
  color: #999;
  margin-left: 20rpx;
}

.date {
  font-size: 24rpx;
  margin-left: 30rpx;
  color: #999;
  vertical-align: middle;
}

.title {
  margin-left: 40rpx;
  font-size: 36rpx;
  font-weight: 700;
  margin-top: 30rpx;
  letter-spacing: 2px;
  color: #4b556c;
}

.tool {
  margin-top: 20rpx;
}

.circle-img {
  float: right;
  margin-right: 40rpx;
  vertical-align: middle;
}
.circle-img image{
  width: 90rpx;
  height: 90rpx;
}
.share-img {
  margin-left: 30rpx;
}

.horizon {
  width: 660rpx;
  height: 1px;
  background-color: #e5e5e5;
  vertical-align: middle;
  position: relative;
  top: 46rpx;
  margin: 0 auto;
  z-index: -99;
}

.detail{
  color: #666;
  margin-left: 30rpx;
  margin-top: 20rpx;
  margin-right: 30rpx;
  line-height: 44rpx;
  letter-spacing: 2px;
}

.audio{
  width: 102rpx;
  height: 110rpx;
  position: absolute;
  left: 50%;
  margin-left: -51rpx;
  top: 180rpx;
  opacity: 0.6;  // 设置透明度为0.6
}

app.wxss代码:

text{
  font-family: MicroSoft Yahei;
  font-size: 24rpx;
}

完功能果:
4858美高梅 14


准备工作

大家利用 jsonp协作node代理 借用了qq音乐接口完成的 音乐播放器

这是jsonp代码

/**
 * Created by majunchang on 2017/7/23.
 */
import originJsonp from 'jsonp'

// 三个参数分别为 目标url 需要拼接在url上的参数 以及jsonp插件 需要的option
export default function jsonp(url,paramdata,options) {
  // 在这里引入一个  拼接字符串的方法
  url += (url.indexOf('?')< 0 ? '?':'&')+param(paramdata);

  // 在这里返回一个Promise对象
  return new Promise((resolve,reject)=>{
    // 在这里的data 跟上面的paramdata是不一样的  一个是 json的返回对象  一个是你传入的参数
    originJsonp(url,options,(err,data)=>{
      if(!err){
        resolve(data)
      }
      else {
        reject(err)
      }
    })
  })
}


function param(paramdata) {
  let url='';
  for(var k in paramdata){
    //  对参数对象里的每一项进行判断
    let value = paramdata[k] ==  undefined ? '': paramdata[k];
    url+= `&${k}=${encodeURIComponent(value)}`
  }
  // 循环结束  url 拼接完毕 将其返回
  return url
}

那是布署接口的js

/**
 * Created by majunchang on 2017/7/23.
 */
import jsonp from 'common/js/jsonp'
import {commonParams,options} from './config'
import axios from 'axios'

export function getRecommend() {
  const url = 'https://c.y.qq.com/musichall/fcgi-bin/fcg_yqqhomepagerecommend.fcg'

  const paramData = Object.assign({},commonParams,{
    platform: 'h5',
    uin: 0,
    needNewCode: 1
  })

  return jsonp(url,paramData,options)
}

// 歌单列表
export function getDiscList() {
  const url='/api/getDiscList';

  // 需要拼接的数据
  const data = Object.assign({},commonParams,{
    platform: 'yqq',
    hostUin: 0,
    sin: 0,
    ein: 29,
    sortId: 5,
    needNewCode: 0,
    categoryId: 10000000,
    rnd: Math.random(),
    format: 'json'
  })

  return axios.get(url,{
      params:data
  }).then((res)=>{
    console.log(res);
    return Promise.resolve(res.data);
  })
}

那是nodejs 代码 仅仅推荐页面 用到了这么些axios
其他的都是选择接口配置jsonp实现的

var app = express()
var apiRoutes = express.Router()

apiRoutes.get('/getDiscList',function (req,res) {
  var url = 'https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg';
  axios.get(url,{
    headers: {
      referer: 'https://c.y.qq.com/',
      host: 'c.y.qq.com'
    },
    params:req.query
  }).then((response)=>{
    res.json(response.data)
  }).catch((e)=>{
    console.log(e);
  })

})
app.use('/api',apiRoutes);

开端化音乐

首先,在properties中收取页面传来的音乐文件地址,

music: {
  type: String,
  value: '',
  observer: function (newVal) {
    this._initMusic(newVal)
  }
}

此处的拍卖是,1旦接收到页面传来的 music 地址,就起头化音乐:

_initMusic: function (newVal) {
  // 当页面传来新的music时,先销毁之前的audioCtx,否则页面会很嗨
  if (this.data.audioCtx) {
    this.data.audioCtx.destroy()
  }
  if (newVal) {
    var audioCtx = wx.createInnerAudioContext()
    this.setData({
        audioCtx: audioCtx
    })
    if (this.data.audioStatus == '1') {
        audioCtx.autoplay = true
    }
    audioCtx.loop = true
    audioCtx.src = newVal
  }
}

 audioStatus 用来记录音乐广播状态,在data中私下认可设置为1:

data: {
    icon: '',
    audioStatus: 1,
    audioCtx: '',
    musicClass: 'music-on'
}

wxml文件里,只用一个 <image> 标签:

<image class='music {{ rotate && musicClass }}'  
        style="{{ musicStyle }}"  
        src="{{ icon }}"  
        bindtap='_switch'  
        wx:if="{{ music }}"></image>

其中, icon 在组件ready()时赋值成播放状态的icon:

ready() {
    this.setData({
      icon: this.data.iconOn
    })
}

布置全局导航栏颜色

地点把基本的静态页面做完了,然而导航栏颜色还不太对,而且少了个标识文字,所以未来就来把那几个岗位的体制完善好。
app.json文件内容:

{
  "pages": [
    "pages/welcome/welcome",
    "pages/posts/post",
    "pages/posts/post-detail/post-detail"
  ],
  "window": {
    "navigationBarBackgroundColor": "#405f80"
  }
}

welcome.json文件内容:

{
  "navigationBarBackgroundColor": "#b3d4db"
}

post.json文件内容:

{
    "navigationBarTitleText": "文与字"
}

post-detail.json文件内容:

{
  "navigationBarTitleText": "阅读"
}

完功用果:
4858美高梅 15


推荐页面

应用jsonp的法门 获取到多少

音乐旋转效果

音乐广播时的旋转效果,是用css动画落成的,wxss文件如下:

.music {
  position: absolute;
  z-index: 99;
  -webkit-animation-iteration-count: infinite;
}
/* 旋转class */
.music-on {
  animation: music-rotate 4s linear infinite;
}
/* 旋转动画 */
@keyframes music-rotate {
  0% {
    transform: rotateZ(0deg);
  }

  100% {
    transform: rotateZ(360deg);
  }
}

当 rotate 为true时,使 musicClass 的值为 music-on,就能落到实处旋转了。

当然, musicClass 供给用 this.setData 的主意来切换值。

爆丑照:

4858美高梅 16

动用数据填充音信详情页面

率先是postId的拿走,因为差别的postId要求输出分歧的小说详情数据:
一.在post.js的navigateTo方法的url参数中,加上二个id参数:

onPostTap: function(event){
    // 从事件源中获取postId数据
    var postId = event.currentTarget.dataset.postid;
    //console.log("on post id is " + postId);
    wx.navigateTo({
      url: 'post-detail/post-detail?id=' + postId,  // 通过url传递postId
    })
  },

二.然后在post-detail.js中,写3个onLoad函数把id得到获得:

Page({
  onLoad:function(option){
    var postId = option.id; // 这里的id对应的是url参数上的id
    console.log(postId);
  }
})

三.编写翻译之后,点击不一样的篇章,看看控制斯特拉斯堡是还是不是有出口相应的postId,有出口的话就印证得到成功。

姣好上述操作后,就足以把音讯详情页面包车型客车数目放进数据文件中,然后举办多少绑定:
post-data.js文件内容:

// 将数据整合成数组类型
var local_database = [
  {
    date: "Jan 06 2018",
    title: "正是虾肥蟹壮时",
    imgSrc: "post/crab.png",
    avatar: "vatar/1.png",
    content: "“山明水净夜来霜,数树深红出浅黄。试上高楼清入骨,岂如春色嗾人狂。”金秋时节,天高云淡,秋风送爽,气候宜人。秋风秋阳中,硕果坠挂枝头,玉米抚须含笑,高粱引颈高歌,豆荚饱满圆润。",
    reading: "112",
    collection: "96",
    headImgSrc: "post/crab.png",
    author: "zero",
    dataTime:"24小时前",
    detail: "“山明水净夜来霜,数树深红出浅黄。试上高楼清入骨,岂如春色嗾人狂。”金秋时节,天高云淡,秋风送爽,气候宜人。秋风秋阳中,硕果坠挂枝头,玉米抚须含笑,高粱引颈高歌,豆荚饱满圆润。棉桃鼓胀欲裂,水稻灌浆初熟,世间万物经过春的孕育,夏的生长,即将抵达收获的季节。在这瓜果飘香、稻黍起舞的召唤声中,又是一度蟹肥虾壮时。地处黄海之滨的小城,在秋风的抚慰、秋阳的光照下,瞬间也喧嚣起来。任意走进城中的每一个菜市场,在显眼的位置上,冲入耳际的是此起彼伏的吆喝声,映入眼帘的是那些小商小贩们抢占有利地势将一只只塑料箱一字排开的情景。浅箱中,健壮的对虾、竹节虾在水中跳跃,舒展着弯曲的身体;深箱中,一贯横行霸道的螃蟹拥挤在狭小的空间里,相互肆意践踏,有些不甘蜗居的螃蟹,顺着笔直的箱壁艰难地攀爬着,虽经百般努力,终以失败而告终。那些聚集在网兜里的螃蟹,更是不甘寂寞,身体被束缚着无法动弹,便利用可以自由呼吸的嘴巴,于窸窸窣窣中不停地吐着一串串泡沫,以示抗议,也以此证明自己是个活物。特别是那些个头较大的螃蟹,仿佛知道自己的身价不菲,为此,更是气宇轩昂,自以为是。也许,它们是得到垂青和恩宠的一类吧,受到了特别的眷顾,活动的空间相对较大,所以也更加肆无忌惮。只要有人试图靠近,便会举着那两只肥硕的大螯向你示威,仿佛在警告你:别碰我,否则休怪我无礼!",
    postId: 0,
  },
  {
    date: "Jan 03 2018",
    title: "比利·林恩的中场战事",
    imgSrc: "post/bl.png",
    avatar: "vatar/2.png",
    content: "伊拉克战争时期,来自美国德州的19岁技术兵比利·林恩(乔·阿尔文 Joe Alwyn 饰)因为一段偶然拍摄的视频而家喻户晓。那是一次规模不大却激烈非常的遭遇战,战斗中林恩所在的B班班长(范·迪塞尔 Vin Diesel 饰)遭到当地武装分子的伏击和劫持,而林恩为了营救班长不惜铤而走险冲锋陷阵。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/bl.png",
    dataTime: "一天前",
    author: "妮可",
    detail: "伊拉克战争时期,来自美国德州的19岁技术兵比利·林恩(乔·阿尔文 Joe Alwyn 饰)因为一段偶然拍摄的视频而家喻户晓。那是一次规模不大却激烈非常的遭遇战,战斗中林恩所在的B班班长(范·迪塞尔 Vin Diesel 饰)遭到当地武装分子的伏击和劫持,而林恩为了营救班长不惜铤而走险冲锋陷阵。视频公布于世让他成为全美民众所崇拜的英雄,然而却鲜有人理解他和战友们所经历的一切。为了安葬班长,B班得到了短暂的休假,因此他们得以受邀参加一场在德州举行的橄榄球比赛。林恩的姐姐因某事件深感愧疚,她希望弟弟能借此机缘回归普通生活。而周围的经纪人、球迷、大老板、普通民众则对战争、卫国、士兵有着各种各样想当然的理解。球场上的庆典盛大开幕,林恩和战友们的心却愈加沉重与焦躁…… ",
    postId: 1,
  },
  {
    date: "Jan 05 2018",
    title: "肖申克的救赎",
    imgSrc: "post/xs.jpg",
    avatar: "vatar/3.png",
    content: "20世纪40年代末,小有成就的青年银行家安迪(蒂姆·罗宾斯 Tim Robbins 饰)因涉嫌杀害妻子及她的情人而锒铛入狱。在这座名为肖申克的监狱内,希望似乎虚无缥缈,终身监禁的惩罚无疑注定了安迪接下来灰暗绝望的人生。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/xs.jpg",
    dataTime: "两天前",
    author: "John",
    detail: "20世纪40年代末,小有成就的青年银行家安迪(蒂姆·罗宾斯 Tim Robbins 饰)因涉嫌杀害妻子及她的情人而锒铛入狱。在这座名为肖申克的监狱内,希望似乎虚无缥缈,终身监禁的惩罚无疑注定了安迪接下来灰暗绝望的人生。未过多久,安迪尝试接近囚犯中颇有声望的瑞德(摩根·弗里曼 Morgan Freeman 饰),请求对方帮自己搞来小锤子。以此为契机,二人逐渐熟稔,安迪也仿佛在鱼龙混杂、罪恶横生、黑白混淆的牢狱中找到属于自己的求生之道。他利用自身的专业知识,帮助监狱管理层逃税、洗黑钱,同时凭借与瑞德的交往在×××中间也渐渐受到礼遇。表面看来,他已如瑞德那样对那堵高墙从憎恨转变为处之泰然,但是对自由的渴望仍促使他朝着心中的希望和目标前进。而关于其罪行的真相,似乎更使这一切朝前推进了一步…… ",
    postId: 2,
  },
  {
    date: "Jan 01 2018",
    title: "霸王别姬",
    imgSrc: "post/bj.jpg",
    avatar: "vatar/4.png",
    content: "段小楼(张丰毅)与程蝶衣(张国荣)是一对打小一起长大的师兄弟,两人一个演生,一个饰旦,一向配合天衣无缝,尤其一出《霸王别姬》,更是誉满京城,为此,两人约定合演一辈子《霸王别姬》。但两人对戏剧与人生关系的理解有本质不同,段小楼深知戏非人生,程蝶衣则是人戏不分。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/bj.jpg",
    dataTime: "三天前",
    author: "Jack",
    detail: "段小楼(张丰毅)与程蝶衣(张国荣)是一对打小一起长大的师兄弟,两人一个演生,一个饰旦,一向配合天衣无缝,尤其一出《霸王别姬》,更是誉满京城,为此,两人约定合演一辈子《霸王别姬》。但两人对戏剧与人生关系的理解有本质不同,段小楼深知戏非人生,程蝶衣则是人戏不分。段小楼在认为该成家立业之时迎娶了名妓菊仙(巩俐),致使程蝶衣认定菊仙是可耻的第三者,使段小楼做了叛徒,自此,三人围绕一出《霸王别姬》生出的爱恨情仇战开始随着时代风云的变迁不断升级,终酿成悲剧。",
    postId: 3,
  },
  {
    date: "Jan 08 2018",
    title: "这个杀手不太冷",
    imgSrc: "post/ss.jpg",
    avatar: "vatar/5.png",
    content: "里昂(让·雷诺饰)是名孤独的×××,受人雇佣。一天,邻居家小姑娘马蒂尔达(纳塔丽·波特曼饰)敲开他的房门,要求在他那里暂避杀身之祸。原来邻居家的主人是警方缉毒组的眼线,只因贪污了一小包×××而遭恶警(加里·奥德曼饰)杀害全家的惩罚。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/ss.jpg",
    dataTime: "四天前",
    author: "Bill",
    detail: "里昂(让·雷诺饰)是名孤独的×××,受人雇佣。一天,邻居家小姑娘马蒂尔达(纳塔丽·波特曼饰)敲开他的房门,要求在他那里暂避杀身之祸。原来邻居家的主人是警方缉毒组的眼线,只因贪污了一小包×××而遭恶警(加里·奥德曼饰)杀害全家的惩罚。马蒂尔达得到里昂的留救,幸免于难,并留在里昂那里。里昂教小女孩使枪,她教里昂法文,两人关系日趋亲密,相处融洽。女孩想着去×××,反倒被抓,里昂及时赶到,将女孩救回。混杂着哀怨情仇的正邪之战渐次升级,更大的冲突在所难免…… ",
    postId: 4,
  },
  {
    date: "Jan 04 2018",
    title: "阿甘正传",
    imgSrc: "post/ag.jpg",
    avatar: "vatar/1.png",
    content: "阿甘(汤姆·汉克斯 饰)于二战结束后不久出生在美国南方阿拉巴马州一个闭塞的小镇,他先天弱智,智商只有75,然而他的妈妈是一个性格坚强的女性,她常常鼓励阿甘“傻人有傻福”,要他自强不息。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/ag.jpg",
    dataTime: "五天前",
    author: "Tony",
    detail: "阿甘(汤姆·汉克斯 饰)于二战结束后不久出生在美国南方阿拉巴马州一个闭塞的小镇,他先天弱智,智商只有75,然而他的妈妈是一个性格坚强的女性,她常常鼓励阿甘“傻人有傻福”,要他自强不息。阿甘像普通孩子一样上学,并且认识了一生的朋友和至爱珍妮(罗宾·莱特·潘 饰),在珍妮和妈妈的爱护下,阿甘凭着上帝赐予的“飞毛腿”开始了一生不停的奔跑。阿甘成为橄榄球巨星、越战英雄、乒乓球外交使者、亿万富翁,但是,他始终忘不了珍妮,几次匆匆的相聚和离别,更是加深了阿甘的思念。有一天,阿甘收到珍妮的信,他们终于又要见面了……",
    postId: 5,
  },
]

// 设置一个数据出口
module.exports = {
  // 输出的是一个Array对象
  postList: local_database,
}

post-detail.js文件内容:

var postsData = require('../../../data/posts-data.js')

Page({
  onLoad:function(option){
    var postId = option.id; // 这里的id对应的是url参数上的id
    var postData=postsData.postList[postId];
    this.setData({
        postData
    });
  }
})

post-detail.wxml文件内容:

<view class='container'>
  <image src='{{postData.headImgSrc}}' class='head-iamge'></image>
  <image class='audio' src='music/music-start.png'></image>
  <view class='author-date'>
    <image src='{{postData.avatar}}' class='avatar' ></image>
    <text class='author'>{{postData.author}}</text>
    <text class='const-text'>发表于</text>
    <text class='date'>{{postData.dataTime}}</text>
  </view>
  <text class='title'>{{postData.title}}</text>
  <view class='tool'>
    <view class='circle-img'>
      <image src='icon/collection.png'></image>
      <image class='share-img' src='icon/share.png'></image>
    </view>
    <view class='horizon'></view>
  </view>
  <text class='detail'>{{postData.detail}}</text>
</view>

运作效果:
4858美高梅 17


轮播图部分

https://c.y.qq.com/musichall/fcgi-bin/fcg\_yqqhomepagerecommend.fcg

1部分代码如下:

        <slider>
            <div v-for="item in recommends">
              <a :href="item.linkUrl">
                <img class="needsclick" @load='loadImg' :src="item.picUrl">
              </a>
            </div>
          </slider>

 methods: {
      _initScroll(){
          console.log(this.listenScroll);
        if (!this.$refs.wrapper) {
          return
        }
        this.scroll = new BScroll(this.$refs.wrapper, {
          probeType: this.probeType,
          click: this.click
        })
        if(this.listenScroll){
            let _this = this;
            this.scroll.on('scroll',(pos)=>{
                _this.$emit('scroll',pos);
            })
        }
      }
  1. 采取 better-scroll插件 将轮播图部分空洞成为四个零件 使用solt插槽
    往里面填充内容
  2. 运用插件的情节的连锁api 和轮播组件里面包车型客车 props的 控制图片的轮播速度
    间隔时间 和是或不是轮播 在此基础上 增加dots 也等于图形底部的圆点
  3. 监听window的resize事件 当用户改变荧屏的时候 轮播效果不会爆发变动
  4. 访问连接 以及再次来到格式 数据

音乐控制

缓存Storage的着力用法

在篇章详情页中我们需求达成2个稿子收藏的效益,由于大家从不行使到服务器,所以利用本地缓存来记录这些小说是还是不是被用户收藏的一个场所。

小程序中提供了二个setStorageSync方法来落到实处缓存,从章程名也得以见到这一个措施是带有同步的。除却还有1个异步的缓存方法setStorage,那么些艺术能够用来异步缓存数据。

注:和缓存相关的不二等秘书诀,例如获得缓存数据、删除缓存数据等办法,都有共同和异步多个,方法名末尾有Sync的表示同步,不然是异步。

先是演示一下setStorageSync方法的使用办法:

// 第一个参数是键,第二个参数则是需要存储的数据
wx.setStorageSync('key', "Test");

自己在post-detail.js文件中的onLoad方法里投入了以上那段代码,此时自小编点击进入文章详情页面,就会缓存这么些数额,缓存数据在Storage界面查看:
4858美高梅 18

在小程序中,假设用户不去主动搞定缓存数据,那么数量就会平素存在,所以现在尽管小编关闭开发工具或许另行展开编写翻译,这么些数目都会设有,除非本人积极删掉它。

经过键能够变动缓存数据:

wx.setStorageSync('key', {
      game:"eat chicken",
      developer:"LD",
});

运营结果:
4858美高梅 19

取得缓存的多寡:

<!-- 在收藏图标上加上一个事件 -->
<image catchtap='onCollectionTap' src='icon/collection.png'></image>

动用getStorageSync方法即可得到缓存数据:

onCollectionTap:function(event){
    var game=wx.getStorageSync('key');
    console.log(game);
}

运转结果:
4858美高梅 20

删除缓存数据:

<!-- 在分享图标上加上一个事件 -->
<image catchtap='onShareTap' class='share-img' src='icon/share.png'></image>

采纳removeStorageSync方法即可删除缓存数据:

onShareTap:function(event){
    wx.removeStorageSync('key');
},

运维结果,能够见到数据已经不存在了:
4858美高梅 21

去除全体缓存数据的点子:

wx.clearStorageSync();

注:小程序分明缓存数据的轻重上限是10MB


歌单列表部分

https://c.y.qq.com/splcloud/fcgi-bin/fcg\_get\_diss\_by\_tag.fcg

  1. 由于qq音乐 对访问对象 做了限制 所以大家经过安顿代理的方法 举行访问
    npm run dev的时候 会在dev-server中运营 我们结合axios和express框架
    配置利用代理
  2. 出席loading组件和懒加载组件 在网速较低的动静下 进步了用户的体会
  3. 后台代理代码

var app = express()
var apiRoutes = express.Router()

apiRoutes.get('/getDiscList',function (req,res) {
  var url = 'https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg';
  axios.get(url,{
    headers: {
      referer: 'https://c.y.qq.com/',
      host: 'c.y.qq.com'
    },
    params:req.query
  }).then((response)=>{
    res.json(response.data)
  }).catch((e)=>{
    console.log(e);
  })

})
app.use('/api',apiRoutes);

手动切换

手动点击时,用取反的逻辑控制音乐的广播和刹车:

_switch: function () {
  // 如果是播放就停止   
  if (this.data.audioStatus) {
    this.setData({
      audioStatus: 0,
      icon: this.data.iconOff,
      musicClass: ''
    })
    this.data.audioCtx.pause()
  // 如果是停止就播放 
  } else {
    this.setData({
      audioStatus: 1,
      icon: this.data.iconOn,
      musicClass: 'music-on'
    })
    this.data.audioCtx.play()
  }
}

动用缓存完结小说收藏功效

落实这一个功能大家须求接纳到多个图标举办状态的交替,由于小程序中并未有document,大家须要动用if判断来兑现这几个效果。

post-detail.wxml代码如下:

<!-- 判断collected的值是否为真,是的话就显示src中指定的图片 -->
<image wx:if="{{collected}}" catchtap='onCollectionTap' src='icon/collection.png'></image>
<!-- 否则显示这张图片 -->
<image wx:else catchtap='onCollectionTap' src='icon/collection-anti.png'></image>

post-detail.js代码如下:

var postsData = require('../../../data/posts-data.js')

Page({
  data:{

  },
  onLoad: function (option) {
    var postId = option.id; // 这里的id对应的是url参数上的id
    // 把postId设置到数据集里,这样就能够全局获取
    this.data.currentPostId = postId;
    var postData = postsData.postList[postId];
    this.setData({
      postData
    });

    // 从缓存中获取数据,键值对形式的
    var postsCollected = wx.getStorageSync('posts_collected');
    // 判断数据是否不为空
    if (postsCollected) {
      // 不为空就拿出与postId对应的下标值
      var postsCollected = postsCollected[postId];
      // 并将值更新到数据绑定里
      this.setData({
        collected: postsCollected
      });
    } else {
      // 如果为空就赋值一个空对象
      var postsCollected = {}
      // 并把与postId对应的下标中的值设置为false
      postsCollected[postId] = false;
      // 更新到缓存里
      wx.setStorageSync('posts_collected', postsCollected);
    }
  },

  // 点击事件方法
  onCollectionTap: function (event) {
    // 获取缓存数据
    var postsCollected = wx.getStorageSync('posts_collected');
    // 从数据集中获取postId
    var postCollected = postsCollected[this.data.currentPostId];
    // 收藏变成未收藏,未收藏变成收藏
    postCollected = !postCollected;
    postsCollected[this.data.currentPostId] = postCollected;
    // 更新文章是否收藏的缓存值
    wx.setStorageSync('posts_collected', postsCollected);
    // 更新数据绑定变量,从而实现切换图片
    this.setData({
      collected: postCollected
    });
  },

})

运营效果:

未收藏状态:
4858美高梅 22

深藏状态:
4858美高梅 23


演唱者页面

分为明星列表页和演唱者详情页 歌唱家列表页需要做出左右联合浮动 类似于
手提式有线话机通信录那样的 歌星详情页要要出模拟原生app的 滑动感觉

别的境况

还要,还要对下列情况做拍卖:

  • 分享时,进入选好友界面、音乐截止,分享回来后,音乐未有继承播放
  • 此后页面跳转到下八个页面时,音乐还在连续
  • 后来页面撤回到上3个页面时,音乐还在持续

化解的措施,是在组件的methods中又写了七个艺术:

// 写在组件的methods中:

// 在引用组件页面的onShow()中调用
//  否则,如果当发生分享页面行为并返回时,音乐不会自动播放
onShow: function () {
  if (this.data.music && this.data.audioStatus) {
    this.data.audioCtx.play()
  }
},

// 在引用组件页面的onHide()中调用
//  否则,在跳转到下一个页面后,音乐还在继续
onHide: function () {
  if (this.data.music && this.data.audioStatus) {
    this.data.audioCtx.pause()
  }
  this.setData({
    animationData: {}
  })
}

那五个法子分别在页面中的 onShow 和 onHide 中调用,调用情势正是父组件获取到子组件实例对象:

例如,给<music>零件加id为”music-componet”,调用时正是:

// 写在调用页面中

onShow: function () {
    this.selectComponent('#music-component').onShow()
},

onHide: function () {
    this.selectComponent('#music-component').onHide()
}

最后,在组件的detached中也调用一下 onHide 方法:

// 页面关闭时销毁音乐
detached() {
    this.onHide()
}

交互反馈 wx.showToast

上述我们兑现了收藏和未收藏图标的一个轮流效率,可是还贫乏了个提示意义,在用户点击收藏时要唤醒用户收藏成功,再度点击则必要提醒用户裁撤成功。

小程序提供了多少个达成互动反馈功用的API,详情参见以下官方文档:

咱俩需求动用到内部八个API,分别是wx.showToast、wx.showModal、wx.showActionSheet。

先是来选用wx.showToast那么些API,在事件措施中,插手如下代码:

wx.showToast({
      // 使用三元表达式来判断状态
      title: postCollected ? '收藏成功!' :'取消成功!',
      // 设置图标停留的时间,单位是毫秒
      duration: 1000,
      // icon可以设置图标,默认就是success
      icon: "success",
});

运营作效果果:
4858美高梅 24
4858美高梅 25


演唱者列表页

将他封装成了 一个 基本组件 大家需求贯彻以下职能

  • 滑动左侧 左侧的不等字母 要出示当相应的颜料
  • 点击右侧的首字母 左右要滚动到响应的岗位

福寿双全详解:

  1. 子组件使用事件监听 scroll事件 然后触发父组件的点子
    遵照滑动距离(约等于y值)来跟高度数组作相比
  2. 点击左侧的首字母之后 触发父组件的点击事件 将高度数组的应和索引的值
    赋给scrolly 然后选择watch 去监听这几个值 最终调用better-scroll的方式使页面滑动到对应的职分
  3. 要同盟移动端的touch事件 start move end 以及选拔e.touches[0]

使用

你可以

  • 通过阅读本文,依据自家实际意况写一个
  • 或者,直接凑合用

操作反馈wx.showModal

wx.showModal能够显得模态弹窗,大家得以把wx.showModal与wx.showToast相结合使用。

修改代码如下:

var postsData = require('../../../data/posts-data.js')

Page({
  data: {

  },
  onLoad: function (option) {
    var postId = option.id; // 这里的id对应的是url参数上的id
    // 把postId设置到数据集里,这样就能够全局获取
    this.data.currentPostId = postId;
    var postData = postsData.postList[postId];
    this.setData({
      postData
    });

    // 从缓存中获取数据
    var postsCollected = wx.getStorageSync('posts_collected');
    // 判断数据是否不为空
    if (postsCollected) {
      // 不为空就拿出与postId对应的下标值
      var postsCollected = postsCollected[postId];
      // 并将值更新到数据绑定里
      this.setData({
        collected: postsCollected
      });
    } else {
      // 如果为空就赋值一个空对象
      var postsCollected = {}
      // 并把与postId对应的下标中的值设置为false
      postsCollected[postId] = false;
      // 更新到缓存里
      wx.setStorageSync('posts_collected', postsCollected);
    }
  },

  // 点击事件方法
  onCollectionTap: function (event) {
    // 获取缓存数据
    var postsCollected = wx.getStorageSync('posts_collected');
    // 获取postId
    var postCollected = postsCollected[this.data.currentPostId];
    // 收藏变成未收藏,未收藏变成收藏
    postCollected = !postCollected;
    postsCollected[this.data.currentPostId] = postCollected;

    // 自定义函数也需要使用this来访问
    this.showModal(postsCollected, postCollected);
  },

  showModal: function (postsCollected, postCollected){
    // 把this指代的Page对象先存储起来
    var that = this;
    wx.showModal({
      title: '收藏',
      content: postCollected ? '是否收藏该文章?' :'是否取消收藏该文章?',
      showCancel: 'true',
      cancelText: '取消',
      cancelColor: '#333',
      confirmText: '确认',
      confirmColor: '#405f80',
      success:function(res){
        if(res.confirm){
          // 更新文章是否收藏的缓存值
          wx.setStorageSync('posts_collected', postsCollected);
          // 更新数据绑定变量,从而实现切换图片
          that.setData({
            collected: postCollected
          });
          that.showToast(postsCollected, postCollected);
        }
      },
    });
  },

  showToast: function (postsCollected, postCollected){
    wx.showToast({
      // 使用三元表达式来判断状态
      title: postCollected ? '收藏成功!' : '取消成功!',
      // 设置图标停留的时间,单位是毫秒
      duration: 1000,
      // icon可以设置图标,默认就是success
      icon: "success",
    });
  },
})

运转效果:
收藏:
4858美高梅 26
4858美高梅 27

收回收藏:
4858美高梅 28
4858美高梅 29

注:在其实支付中那种花费低的操作是不要求把相互反馈做得那样麻烦的,一般只行使showToast即可。所谓资本指的是误操作带来的损失,假若费用低的操作交互反馈太费事的话,会倍感体验倒霉。


有关的代码

onShortcutTouchStart(e){
        // 我们的目的是获取到  你触摸的这个的index索引值
        let anchorIndex = getData(e.target, 'index');
        // js触摸事件 http://www.jianshu.com/p/832f36531df9
        let firstTouch = e.touches[0];
        this.touch.y1 = firstTouch.pageY;
        this.touch.anchorIndex1 = anchorIndex;
        this._scroll(anchorIndex)
        this.$refs.listView.scrollToElement(this.$refs.listGroup[anchorIndex], 0)
      },
      onShortcutTouchMove(e){
        let touchmove = e.touches[0];
        this.touch.y2 = touchmove.pageY;
        let chazhi = (this.touch.y2 - this.touch.y1) / keyWordHeight | 0;

        this.touch.anchorIndex2 = parseInt(this.touch.anchorIndex1) + chazhi;
        // 使用滚动具体距离事件
        this._scroll(this.touch.anchorIndex2)
        this.$refs.listView.scrollToElement(this.$refs.listGroup[this.touch.anchorIndex2], 0)
      },
      scroll(pos){
        this.scrollY = pos.y
      },

互相反馈wx.showActionSheet

​showActionSheet可以显得操作菜单,以下使用实际示例演示一下showActionSheet的行使:

壹.在分享图标上丰裕一个点击事件:

<image catchtap='onShareTap' class='share-img' src='icon/share.png'></image>

2.风云代码如下:

onShareTap:function(event){
    var itemList = [
      "分享给微信好友",
      "分享到朋友圈",
      "分享到QQ",
      "分享到微博",
    ]
    wx.showActionSheet({
      itemList: itemList,  // 按钮的文字数组,数组长度最大为6个
      itemColor:"#405f80",  // 设置字体颜色
      success:function(res){
        //res.tapIndex  用户点击的按钮,从上到下的顺序,从0开始
        wx.showModal({
          title: itemList[res.tapIndex],
          content: '现在无法实现分享功能,什么时候能支持还未知',
        })
      }, 
    })
  },

运行效果:
4858美高梅 30
4858美高梅 31

注:到如今甘休,微信小程序合法还未有提供力所能及将小程序直接分享到朋友圈的连锁api,然而有一些曲线救国的方案,能够参照以下两篇文章,或许使用百度、谷歌等搜寻引擎搜索消除方案:


演唱者详情页

技能达成困难:模拟原生移动应用实现 上海滑稽剧团和下落的时候的功能

越多的是介于怎么样使用css+scroll组件 完成那几个意义

scrollY(newVal){
        // 在这里监听 scroll的变化 并改变头部图片的值
        /*
         我们要达到两个效果 第一个效果:歌单列表向上滑动的时候 遮罩层随着向上(有一个向上的最大距离) 往下滑的时候(图片要随着你下滑的距离 有一个放大的效果)
         */
        let translateY = Math.max(this.minTransalteY, newVal);
        let scale = 1;
        let zIndex = 0;
        let blur = 0;
        const percent = Math.abs(newVal / this.imageHeight);
        if (newVal > 0) {
          scale = 1 + percent;
          zIndex = 10;
        } else {
          blur = Math.min(20, percent * 20)
        }
        // 当列表向上滑动的时候 有一个高斯模糊的效果
        this.$refs.layer.style[transform] = `translate3d(0,${translateY}px,0)`;
        this.$refs.filter.style[backdrop] = `blur(${blur}px)`
        if (newVal < this.minTransalteY) {
          zIndex = 10;
          this.$refs.bgImage.style.height = `${leftHeigth}px`;
          this.$refs.bgImage.style.paddingTop = 0;
        } else {
          this.$refs.bgImage.style.paddingTop = '70%'
          this.$refs.bgImage.style.height = 0
        }
        this.$refs.bgImage.style[transform] = `scale(${scale})`
        this.$refs.bgImage.style.zIndex = zIndex
      }

联合异步方法比较

小编们把以前的onCollectionTap方法中的同步获取缓存的诀要改为异步获取缓存的章程,以此来演示同步与异步方法之间的区别,修改代码如下:

onCollectionTap: function (event) {
    // 把当前this指代的当前对象先存储起来
    var that = this;
    // 异步获取缓存数据
    var postsCollected = wx.getStorage({
      key: 'posts_collected',
      success: function (res) {
        var postsCollected = res.data;
        // 获取postId
        var postCollected = postsCollected[that.data.currentPostId];
        // 收藏变成未收藏,未收藏变成收藏
        postCollected = !postCollected;
        postsCollected[that.data.currentPostId] = postCollected;

        that.showModal(postsCollected, postCollected);
      },
    });
  },

如上正是异步方法的兑现情势,与协同方法的要紧分化在于,同步会等待wx.getStorageSync(‘posts_collected’);方法执行完事后才会往下实施,所以借使当拿到缓存得极慢的时候,操作界面就会卡在那。而异步则不会,异步获取缓存数据的时候,代码还会一而再往下实施,异步获取成功之后再实践success里的情势。

注:平日状态下,在小程序中须求求动用异步方法的情事相比较少,建议1旦对异步方法面生的话,最佳不用使用异步方法,不然不仅会让您的代码变得难以阅读,而且很不难埋下局地隐藏bug,也许难以消除的错误。至于使用异步照旧四头,须要依据作业来决定,当能够应用同步的场地下,优先选择同步。


广播详解

音乐广播基本达成

上述我们早已到位了稿子详情页的超越四分之二剧情,以后还剩多个音乐广播效果还未兑现,官方也提供了四个audio组件能够兑现音乐播放。除了组件之外还有相关的API可以动用,在那里大家应用API来达成音乐播放效果,因为使用API的章程相比方便于自定义。

合法文书档案:

API:
组件:

作者们必要采取到八个API,playBackground奥迪(Audi)o以及pauseBackground奥迪o。前者是用于音乐的广播,后者是用来音乐的暂停。

先给音乐图标添加3个轩然大波,并且利用长富运算符来判断图标是体现暂停图标依然起步图标:

<image catchtap='onMusicTap' class='audio' src='{{isPlayingMusic ? "music/music-stop.png" : "music/music-start.png"}}'></image>

事件措施完结代码如下:

data: {
    isPlayingMusic: false
},

onMusicTap: function (event) {
    // 获取数据文件中的数据
    var currentPostId = this.data.currentPostId;
    var postData = postsData.postList[currentPostId];

    // 使用变量来记录音乐的状态
    var isPlayingMusic = this.data.isPlayingMusic;
    if (isPlayingMusic) {
      // 暂停音乐
      wx.pauseBackgroundAudio();
      // 改变状态
      this.setData({
        isPlayingMusic : false
      });

    } else {
      wx.playBackgroundAudio({
        // 流媒体文件的URL,目前支持的格式有 m4a, aac, mp3, wav
        dataUrl: postData.music.url,
        // 音乐标题
        title: postData.music.title,
        // 音乐封面URL
        coverImgUrl: postData.music.coverImg,
      })
      // 改变状态
      this.setData({
        isPlayingMusic: true
      });
    }
  },

注:dataUrl只好够是引用流媒体文件,不可知利用本地的音乐文件,coverImgUrl也是这么,因为小程序的轻重缓急限制是1M,2个音乐文件都不止1M了,所以只好选拔流媒体文件的UQashqaiL方式引进音乐。coverImgUrl引进的图形唯有在真机上才能来看获得。

数据文件内容如下,扩展了音乐连接、音乐标题、音乐图片属性:

// 将数据整合成数组类型
var local_database = [
  {
    date: "Jan 06 2018",
    title: "正是虾肥蟹壮时",
    imgSrc: "post/crab.png",
    avatar: "vatar/1.png",
    content: "“山明水净夜来霜,数树深红出浅黄。试上高楼清入骨,岂如春色嗾人狂。”金秋时节,天高云淡,秋风送爽,气候宜人。秋风秋阳中,硕果坠挂枝头,玉米抚须含笑,高粱引颈高歌,豆荚饱满圆润。",
    reading: "112",
    collection: "96",
    headImgSrc: "post/crab.png",
    author: "zero",
    dataTime:"24小时前",
    detail: "“山明水净夜来霜,数树深红出浅黄。试上高楼清入骨,岂如春色嗾人狂。”金秋时节,天高云淡,秋风送爽,气候宜人。秋风秋阳中,硕果坠挂枝头,玉米抚须含笑,高粱引颈高歌,豆荚饱满圆润。棉桃鼓胀欲裂,水稻灌浆初熟,世间万物经过春的孕育,夏的生长,即将抵达收获的季节。在这瓜果飘香、稻黍起舞的召唤声中,又是一度蟹肥虾壮时。地处黄海之滨的小城,在秋风的抚慰、秋阳的光照下,瞬间也喧嚣起来。任意走进城中的每一个菜市场,在显眼的位置上,冲入耳际的是此起彼伏的吆喝声,映入眼帘的是那些小商小贩们抢占有利地势将一只只塑料箱一字排开的情景。浅箱中,健壮的对虾、竹节虾在水中跳跃,舒展着弯曲的身体;深箱中,一贯横行霸道的螃蟹拥挤在狭小的空间里,相互肆意践踏,有些不甘蜗居的螃蟹,顺着笔直的箱壁艰难地攀爬着,虽经百般努力,终以失败而告终。那些聚集在网兜里的螃蟹,更是不甘寂寞,身体被束缚着无法动弹,便利用可以自由呼吸的嘴巴,于窸窸窣窣中不停地吐着一串串泡沫,以示抗议,也以此证明自己是个活物。特别是那些个头较大的螃蟹,仿佛知道自己的身价不菲,为此,更是气宇轩昂,自以为是。也许,它们是得到垂青和恩宠的一类吧,受到了特别的眷顾,活动的空间相对较大,所以也更加肆无忌惮。只要有人试图靠近,便会举着那两只肥硕的大螯向你示威,仿佛在警告你:别碰我,否则休怪我无礼!",
    postId: 0,
    music: {
      url: "http://ws.stream.qqmusic.qq.com/C100003507bR0gDKBm.m4a?fromtag=38",
      title: "夜夜夜夜-齐秦",
      coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000001TEc6V0kjpVC.jpg?max_age=2592000"
    }
  },
  {
    date: "Jan 03 2018",
    title: "比利·林恩的中场战事",
    imgSrc: "post/bl.png",
    avatar: "vatar/2.png",
    content: "伊拉克战争时期,来自美国德州的19岁技术兵比利·林恩(乔·阿尔文 Joe Alwyn 饰)因为一段偶然拍摄的视频而家喻户晓。那是一次规模不大却激烈非常的遭遇战,战斗中林恩所在的B班班长(范·迪塞尔 Vin Diesel 饰)遭到当地武装分子的伏击和劫持,而林恩为了营救班长不惜铤而走险冲锋陷阵。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/bl.png",
    dataTime: "一天前",
    author: "妮可",
    detail: "伊拉克战争时期,来自美国德州的19岁技术兵比利·林恩(乔·阿尔文 Joe Alwyn 饰)因为一段偶然拍摄的视频而家喻户晓。那是一次规模不大却激烈非常的遭遇战,战斗中林恩所在的B班班长(范·迪塞尔 Vin Diesel 饰)遭到当地武装分子的伏击和劫持,而林恩为了营救班长不惜铤而走险冲锋陷阵。视频公布于世让他成为全美民众所崇拜的英雄,然而却鲜有人理解他和战友们所经历的一切。为了安葬班长,B班得到了短暂的休假,因此他们得以受邀参加一场在德州举行的橄榄球比赛。林恩的姐姐因某事件深感愧疚,她希望弟弟能借此机缘回归普通生活。而周围的经纪人、球迷、大老板、普通民众则对战争、卫国、士兵有着各种各样想当然的理解。球场上的庆典盛大开幕,林恩和战友们的心却愈加沉重与焦躁…… ",
    postId: 1,
    music: {
      url: "http://ws.stream.qqmusic.qq.com/C100003GdCmG4NkEOR.m4a?fromtag=38",
      title: "鬼迷心窍-李宗盛",
      coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000002xOmp62kqSic.jpg?max_age=2592000"
    }
  },
  {
    date: "Jan 05 2018",
    title: "肖申克的救赎",
    imgSrc: "post/xs.jpg",
    avatar: "vatar/3.png",
    content: "20世纪40年代末,小有成就的青年银行家安迪(蒂姆·罗宾斯 Tim Robbins 饰)因涉嫌杀害妻子及她的情人而锒铛入狱。在这座名为肖申克的监狱内,希望似乎虚无缥缈,终身监禁的惩罚无疑注定了安迪接下来灰暗绝望的人生。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/xs.jpg",
    dataTime: "两天前",
    author: "John",
    detail: "20世纪40年代末,小有成就的青年银行家安迪(蒂姆·罗宾斯 Tim Robbins 饰)因涉嫌杀害妻子及她的情人而锒铛入狱。在这座名为肖申克的监狱内,希望似乎虚无缥缈,终身监禁的惩罚无疑注定了安迪接下来灰暗绝望的人生。未过多久,安迪尝试接近囚犯中颇有声望的瑞德(摩根·弗里曼 Morgan Freeman 饰),请求对方帮自己搞来小锤子。以此为契机,二人逐渐熟稔,安迪也仿佛在鱼龙混杂、罪恶横生、黑白混淆的牢狱中找到属于自己的求生之道。他利用自身的专业知识,帮助监狱管理层逃税、洗黑钱,同时凭借与瑞德的交往在×××中间也渐渐受到礼遇。表面看来,他已如瑞德那样对那堵高墙从憎恨转变为处之泰然,但是对自由的渴望仍促使他朝着心中的希望和目标前进。而关于其罪行的真相,似乎更使这一切朝前推进了一步…… ",
    postId: 2,
    music: {
      url: "http://ws.stream.qqmusic.qq.com/C100004HLusI2lLjZy.m4a?fromtag=38",
      title: "女儿情-万晓利",
      coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000004Wv5BO30pPc0.jpg?max_age=2592000"
    }
  },
  {
    date: "Jan 01 2018",
    title: "霸王别姬",
    imgSrc: "post/bj.jpg",
    avatar: "vatar/4.png",
    content: "段小楼(张丰毅)与程蝶衣(张国荣)是一对打小一起长大的师兄弟,两人一个演生,一个饰旦,一向配合天衣无缝,尤其一出《霸王别姬》,更是誉满京城,为此,两人约定合演一辈子《霸王别姬》。但两人对戏剧与人生关系的理解有本质不同,段小楼深知戏非人生,程蝶衣则是人戏不分。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/bj.jpg",
    dataTime: "三天前",
    author: "Jack",
    detail: "段小楼(张丰毅)与程蝶衣(张国荣)是一对打小一起长大的师兄弟,两人一个演生,一个饰旦,一向配合天衣无缝,尤其一出《霸王别姬》,更是誉满京城,为此,两人约定合演一辈子《霸王别姬》。但两人对戏剧与人生关系的理解有本质不同,段小楼深知戏非人生,程蝶衣则是人戏不分。段小楼在认为该成家立业之时迎娶了名妓菊仙(巩俐),致使程蝶衣认定菊仙是可耻的第三者,使段小楼做了叛徒,自此,三人围绕一出《霸王别姬》生出的爱恨情仇战开始随着时代风云的变迁不断升级,终酿成悲剧。",
    postId: 3,
    music: {
      url: "http://ws.stream.qqmusic.qq.com/C100002mWVx72p8Ugp.m4a?fromtag=38",
      title: "恋恋风尘-老狼",
      coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000001VaXQX1Z1Imq.jpg?max_age=2592000",
    }
  },
  {
    date: "Jan 08 2018",
    title: "这个杀手不太冷",
    imgSrc: "post/ss.jpg",
    avatar: "vatar/5.png",
    content: "里昂(让·雷诺饰)是名孤独的×××,受人雇佣。一天,邻居家小姑娘马蒂尔达(纳塔丽·波特曼饰)敲开他的房门,要求在他那里暂避杀身之祸。原来邻居家的主人是警方缉毒组的眼线,只因贪污了一小包×××而遭恶警(加里·奥德曼饰)杀害全家的惩罚。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/ss.jpg",
    dataTime: "四天前",
    author: "Bill",
    detail: "里昂(让·雷诺饰)是名孤独的×××,受人雇佣。一天,邻居家小姑娘马蒂尔达(纳塔丽·波特曼饰)敲开他的房门,要求在他那里暂避杀身之祸。原来邻居家的主人是警方缉毒组的眼线,只因贪污了一小包×××而遭恶警(加里·奥德曼饰)杀害全家的惩罚。马蒂尔达得到里昂的留救,幸免于难,并留在里昂那里。里昂教小女孩使枪,她教里昂法文,两人关系日趋亲密,相处融洽。女孩想着去×××,反倒被抓,里昂及时赶到,将女孩救回。混杂着哀怨情仇的正邪之战渐次升级,更大的冲突在所难免…… ",
    postId: 4,
    music: {
      url: "http://ws.stream.qqmusic.qq.com/C100000Zn0vS4fKKo8.m4a?fromtag=38",
      title: "沉默是金-张国荣",
      coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000003at0mJ2YrR2H.jpg?max_age=2592000"
    }
  },
  {
    date: "Jan 04 2018",
    title: "阿甘正传",
    imgSrc: "post/ag.jpg",
    avatar: "vatar/1.png",
    content: "阿甘(汤姆·汉克斯 饰)于二战结束后不久出生在美国南方阿拉巴马州一个闭塞的小镇,他先天弱智,智商只有75,然而他的妈妈是一个性格坚强的女性,她常常鼓励阿甘“傻人有傻福”,要他自强不息。",
    reading: "92",
    collection: "65",
    headImgSrc: "post/ag.jpg",
    dataTime: "五天前",
    author: "Tony",
    detail: "阿甘(汤姆·汉克斯 饰)于二战结束后不久出生在美国南方阿拉巴马州一个闭塞的小镇,他先天弱智,智商只有75,然而他的妈妈是一个性格坚强的女性,她常常鼓励阿甘“傻人有傻福”,要他自强不息。阿甘像普通孩子一样上学,并且认识了一生的朋友和至爱珍妮(罗宾·莱特·潘 饰),在珍妮和妈妈的爱护下,阿甘凭着上帝赐予的“飞毛腿”开始了一生不停的奔跑。阿甘成为橄榄球巨星、越战英雄、乒乓球外交使者、亿万富翁,但是,他始终忘不了珍妮,几次匆匆的相聚和离别,更是加深了阿甘的思念。有一天,阿甘收到珍妮的信,他们终于又要见面了……",
    postId: 5,
    music: {
      url: "http://ws.stream.qqmusic.qq.com/C100002I8eGJ28BI17.m4a?fromtag=38",
      title: "朋友-谭咏麟",
      coverImg: "http://y.gtimg.cn/music/photo_new/T002R150x150M000004eGsCN3SUheO.jpg?max_age=2592000"
    }
  },
]

// 设置一个数据出口
module.exports = {
  // 输出的是一个Array对象
  postList: local_database,
}

运营效果:
播放:
4858美高梅 32

暂停:
4858美高梅 33


music的拿走,播放以及和vuex的联合浮动原理详解

graph TD
A[api/singer/getSingerDetail方法获取到数据]-->B(components/singer-detail使用构造函数,初始化songs数组)
B-->C(singer-datail->music-list->song-list 当我们点击歌曲之后 触发了actions 将歌曲列表和歌曲索引传递)
C-->D{  state中存储了歌手 播放 状态是否全屏等信息}

大家在 vuex中贮存的音信 是为了大家在多少个零件之中能够 获取到歌曲的情状从而操作audio标签 来达成大家想要的遵从

切换小说图片

以上大家成功了简约的音乐播放和刹车以及音乐图标的切换,而且也验证了coverImg中引进的图样只有在真机上,进入音乐界面后才能够看出,可是大家也得以将coverImg引进的图纸浮今后篇章详情页上,只须求做八个简练的图形切换即可:

<image src='{{isPlayingMusic ? postData.music.coverImg : postData.headImgSrc}}' class='head-iamge'></image>

运作效果:
播放:
4858美高梅 34

暂停:
4858美高梅 35


歌曲播放界面—》 player.vue文件

切换动作效果部分行使了贝塞尔曲线 唱片的转动部分行使了 css的团团转特效

对于歌词的剖析部分选拔了 插件lyric-parser
https://github.com/ustbhuangyi/lyric-parser

底层的圆圈 使用了svg 以及有关部分性格模拟进程

监听播放事件完善音乐广播

在音乐广播的时候,能够观察会弹出来1个音乐广播的总控开关,我们点击音乐图标的时候能够符合规律的切换图片,可是点击总控开关的时候不会切换图片,那是因为大家只监听了图标上的轩然大波,没有监听音乐广播、暂停的事件。所以我们还供给周到这一点小细节,让点击总控开关的时候也能切换图片,达成这一步要求选用到四个API,onBackground奥迪(Audi)oPlay以及onBackground奥迪oPause,前者用于监听音乐广播,后者用于监听音乐中断。

在onLoad生命周期方法中加进以下代码:

    var that = this;
    // 当音乐播放时将isPlayingMusic状态改为true
    wx.onBackgroundAudioPlay(function(){
      that.setData({
        isPlayingMusic: true
      });
    });

    // 当音乐暂停时将isPlayingMusic状态改为false
    wx.onBackgroundAudioPause(function(){
      that.setData({
        isPlayingMusic: false
      });
    })

进入上述代码后就能够完结点击总控开关也能切换图片,而且以上代码也反映出了数据绑定机制的功利,只必要修改数据集中相应数据的值即可,无需每回都去获取节点目的后才能操作相应的数目标值。


排名页面

排行页面与歌星页面格外相似 对于如此的基础零部件 大家开始展览了复用 代码如下
文件是song—list 差距正是

在排名页面中 大家点击的歌单 使用奖杯图片以及排行的

<template>
  <div class="song-list">
    <ul>
      <li class='item' @click='selectItem(song,index)' v-for="(song,index) in songs">
        <div class="rank" v-show='rank'>

        </div>
        <div class="content">
          <h2 class="name">{{song.name}}</h2>
          <p class="desc">{{getDesc(song)}}</p>
        </div>
      </li>
    </ul>
  </div>
</template>

     getRankClass(index){
        if (index <= 2) {
          return `icon icon${index}`
        } else {
          return 'text'
        }
      },
      getRankText(index){
        if (index > 2) {
          return index + 1
        }
      }        

应用程序生命周期

文章详情页中的音乐广播效果看起来基本是没什么难题了,可是那也仅限于小说详情那四个页面内而已,假设本人点击了广播音乐,然后重返到上拔尖页面,再点击进入文章详情页的话,页面包车型大巴事态就会是起先化时的事态,那时音乐图片就不会自动切换来广播状态的图片。那是因为大家的状态代码写在js文件的Page对象里,会遭到页素不相识命周期的影响,当大家重临上顶尖页面,再点击进入小说详情页时,Page对象会被加载,页面代码就会被重新履行1回,所以音乐图标的气象就会是伊始时的景色。

消除那几个题材我们必要利用全局变量来保存处境,全局变量不会受页不熟悉命周期的震慑,而且在任何页面中都能够博得到全局变量的值。在小程序中全局变量需求写在app.js文件中,该文件中的代码供给写在App对象里,就好像我们的页面代码需求写在Page中平等,Page代表的是二个页面,而App对象则是意味着着全部应用程序,该对象的生命周期也就是应用程序的生命周期。以下是该指标的生命周期方法:

App({

  /**
   * 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
   */
  onLaunch: function () {

  },

  /**
   * 当小程序启动,或从后台进入前台显示,会触发 onShow
   */
  onShow: function (options) {

  },

  /**
   * 当小程序从前台进入后台,会触发 onHide
   */
  onHide: function () {

  },

  /**
   * 当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
   */
  onError: function (msg) {

  }
})

追寻页面

有3个searchBox组件 充当搜索框 上面是一对看好搜索的价签
当大家开始展览搜寻的时候 搜索结果 会复用scroll组件

继承周到音乐广播

如上大家大致介绍了一下有关页面状态与全局变量以及应用程序生命周期,未来就能够使用全局变量来一而再完善音乐播放的作用了:

app.js代码如下:

App({

  globalData:{
    g_isPlayingMusic:false
  },

});

post-detail.js代码如下:

var postsData = require('../../../data/posts-data.js')
// 获得全局的app对象
var app = getApp();

Page({
  data: {
    isPlayingMusic: false
  },

  onLoad: function (option) {

        ......以上代码省略......

    // 当全局变量的状态为播放时,也把页面的状态设置为teur 
    if (app.globalData.g_isPlayingMusic){
      this.setData({
        isPlayingMusic: true
      });
    }

    this.setMusicMonitor();
  },

  // 把监听音乐的事件代码提取出来
  setMusicMonitor:function(){
    var that = this;
    // 当音乐播放时将页面以及全局状态状态改为true
    wx.onBackgroundAudioPlay(function () {
      that.setData({
        isPlayingMusic: true
      });
      app.globalData.g_isPlayingMusic = true;
    });

    // 当音乐暂停时将页面以及全局状态都改为false
    wx.onBackgroundAudioPause(function () {
      that.setData({
        isPlayingMusic: false
      });
      app.globalData.g_isPlayingMusic = false;
    });
  },

              ......以下代码省略......

})

使用全局变量记录状态后,就不会产出在此之前的题材了,那时大家就能够在页面加载时依照全局变量来设置页面变量的情形。


对于搜索框 也正是search-box的input进行截流处理

export  function debounce(func,delay) {
let timer;
  return function(...args){
    //  这是es6的rest参数
    if(timer){
      clearTimeout(timer);
    }
    //console.log(args);
    timer = setTimeout(()=>{
      func.apply(this,args)
    },delay);
  }
}

// 在组件中的create钩子函数中 这样使用 
 created(){
        this.$watch('inputMsg',debounce((newVal)=>{
            // console.log(newVal);
            this.$emit('inputMsg',newVal)
        },200));
    },

音乐播放最终章

除此而外以上的标题之外,小编还找到了四个难题,第三个难点是当大家点击音乐广播时,背景图片会切换,不过我们只要求切换当前页面包车型大巴图片,其他页面不应有也跟着切换,而以此题材正是其他页面也会跟着切换图片,这些标题大家能够通过把页面id存款和储蓄到全局变量里,依据id来控制是哪个页面才会切换图片,那样就能够化解这几个标题。

其次个难题是当大家关闭音乐播放器时,图片不会切换,照旧停留在播音状态,那一个标题大家能够透过wx.onBackground奥迪oStop来缓解。

其多个难题便是当大家在作品A里播放了音乐,然后到作品B上点击音乐播放器的总控开关时,小说B的图样也会随之切换,消除这几个题材不怎么有点麻烦,因为要考虑到点击图标开关和点击音乐播放器开关三种情景,以及回到原来的页面时还需切换图片,小编的缓解思路是利用二个全局变量记录上1个页面,也等于固有页面包车型大巴id,通过那些id来控制切不切换图片。

app.js文件内容如下:

App({

  globalData:{
    g_isPlayingMusic:false,
    g_currentMusicPostId:"",
    g_beforeMusicPostId: ""
  },

});

以下是修改后的post-detail.js文件内容:

var postsData = require('../../../data/posts-data.js')
// 获得全局的app对象
var app = getApp();

Page({
  data: {
    isPlayingMusic: false
  },

  onLoad: function (option) {
    var postId = option.id; // 这里的id对应的是url参数上的id
    // 把postId设置到数据集里,这样就能够全局获取
    this.data.currentPostId = postId;
    var postData = postsData.postList[postId];
    this.setData({
      postData
    });

    // 从缓存中获取数据
    var postsCollected = wx.getStorageSync('posts_collected');
    // 判断数据是否不为空
    if (postsCollected) {
      // 不为空就拿出与postId对应的下标值
      var postsCollected = postsCollected[postId];
      // 并将值更新到数据绑定里
      this.setData({
        collected: postsCollected
      });
    } else {
      // 如果为空就赋值一个空对象
      var postsCollected = {}
      // 并把与postId对应的下标中的值设置为false
      postsCollected[postId] = false;
      // 更新到缓存里
      wx.setStorageSync('posts_collected', postsCollected);
    }

    // 音乐在播放时改变状态为true 
    if (app.globalData.g_isPlayingMusic && app.globalData.g_currentMusicPostId === postId){
      this.setData({
        isPlayingMusic: true
      });
    }

    this.setMusicMonitor();
  },

  // 把监听音乐的事件代码提取出来
  setMusicMonitor:function(){
    var that = this;

    // 监听音乐播放
    wx.onBackgroundAudioPlay(function () {
      // 在原始页面触发播放事件时,切换页面图片,并且记录当前文章的id
      if (app.globalData.g_beforeMusicPostId != "" && app.globalData.g_beforeMusicPostId === that.data.currentPostId){
        that.setData({
          isPlayingMusic: true
        });
        app.globalData.g_isPlayingMusic = true;
        app.globalData.g_currentMusicPostId = that.data.currentPostId;
        app.globalData.g_beforeMusicPostId = app.globalData.g_beforeMusicPostId;

      // 产生原始页面时,或者图标开关被点击时,切换页面图片,并且记录当前文章的id
      } else if (app.globalData.g_beforeMusicPostId == "" || that.data.isPlayingMusic){
        that.setData({
          isPlayingMusic: true
        });
        app.globalData.g_isPlayingMusic = true;
        app.globalData.g_currentMusicPostId = that.data.currentPostId;
        app.globalData.g_beforeMusicPostId = that.data.currentPostId;

      // 在非原始页面触发播放事件时,不切换该页面的图片
      } else{
        that.setData({
          isPlayingMusic: false
        });
        app.globalData.g_isPlayingMusic = true;
        app.globalData.g_currentMusicPostId = app.globalData.g_beforeMusicPostId;
      }
    });

    // 当音乐暂停时将页面以及全局状态都改为false,并且把当前文章的id清空
    wx.onBackgroundAudioPause(function () {
      that.setData({
        isPlayingMusic: false
      });
      app.globalData.g_isPlayingMusic = false;
      app.globalData.g_currentMusicPostId = "";
    });

    // 当音乐停止时将页面以及全局状态都改为false,并且把当前文章以及上一篇文章的id清空
    wx.onBackgroundAudioStop(function(){
      that.setData({
        isPlayingMusic: false
      });
      app.globalData.g_isPlayingMusic = false;
      app.globalData.g_currentMusicPostId = "";
      app.globalData.g_beforeMusicPostId = "";
    });
  },

  //点击事件方法
  onCollectionTap: function (event) {
    // 获取缓存数据
    var postsCollected = wx.getStorageSync('posts_collected');
    // 获取postId
    var postCollected = postsCollected[this.data.currentPostId];
    // 收藏变成未收藏,未收藏变成收藏
    postCollected = !postCollected;
    postsCollected[this.data.currentPostId] = postCollected;

    // 自定义函数也需要使用this来访问
    this.showModal(postsCollected, postCollected);
  },

  showModal: function (postsCollected, postCollected) {
    // 把this指代的Page对象先存储起来
    var that = this;
    wx.showModal({
      title: '收藏',
      content: postCollected ? '是否收藏该文章?' : '是否取消收藏该文章?',
      showCancel: 'true',
      cancelText: '取消',
      cancelColor: '#333',
      confirmText: '确认',
      confirmColor: '#405f80',
      success: function (res) {
        if (res.confirm) {
          // 更新文章是否收藏的缓存值
          wx.setStorageSync('posts_collected', postsCollected);
          // 更新数据绑定变量,从而实现切换图片
          that.setData({
            collected: postCollected
          });
          that.showToast(postsCollected, postCollected);
        }
      },
    });
  },

  showToast: function (postsCollected, postCollected) {
    wx.showToast({
      // 使用三元表达式来判断状态
      title: postCollected ? '收藏成功!' : '取消成功!',
      // 设置图标停留的时间,单位是毫秒
      duration: 1000,
      // icon可以设置图标,默认就是success
      icon: "success",
    });
  },

  onShareTap: function (event) {
    var itemList = [
      "分享给微信好友",
      "分享到朋友圈",
      "分享到QQ",
      "分享到微博",
    ]
    wx.showActionSheet({
      itemList: itemList,
      itemColor: "#405f80",
      success: function (res) {
        //res.cancel  用户是否点击了取消按钮
        //res.tapIndex  数组元素的索引
        wx.showModal({
          title: itemList[res.tapIndex],
          content: '现在无法实现分享功能,什么时候能支持还未知',
        })
      },
    })
  },

  onMusicTap: function (event) {
    var currentPostId = this.data.currentPostId;
    var postData = postsData.postList[currentPostId];

    // 使用变量来记录音乐的状态
    var isPlayingMusic = this.data.isPlayingMusic;
    if (isPlayingMusic) {
      // 暂停音乐
      wx.pauseBackgroundAudio();
      this.setData({
        isPlayingMusic : false
      });

    } else {
      wx.playBackgroundAudio({
        // 流媒体文件的URL,目前支持的格式有 m4a, aac, mp3, wav
        dataUrl: postData.music.url,
        // 音乐标题
        title: postData.music.title,
        // 音乐封面URL
        coverImgUrl: postData.music.coverImg,
      });
      this.setData({
        isPlayingMusic: true
      });
    }
  },
})

如上正是是马到成功了一个骨干的音乐播放效果,这些小说详情页面也正是归根结底大功告成了,即便本身觉得可能还留存有的标题,终究未有两全的代码,假诺后续出现难题后再实行修补。作者个人觉得开发品种应该先支付出三个力所能及上线运营的原型,在营业的历程中再逐月去修复bug,迭代版本。


在查找之后的建议中 点击 会对你点击的指标 约等于总结了明星和歌曲的靶子开始展览区分

selectItem(item) {
        /*
        判断为歌手的 选项 跳转路由 设置mumation 触发事件
         */
        if (item.type === TYPE_SINGER) {
          // 构造一个singer实例
          const singer = new Singer({
            id: item.singermid,
            name: item.singername
          })

          this.$router.push({
            path: `/search/${singer.id}`
          })
          this.setSinger(singer);
        } else {
          this.insertSong(item)
        }
        this.$emit('selected',item)
      },

真机怎么样排除缓存与template的路子难点

在小程序中的缓存数据都以尚羊时效期的,不主动化解的话就会间接留存,在模拟器上大家可以点击工具提供的化解缓存按钮清除缓存数据:
4858美高梅 36

而是假如在真机上,则供给本身手动编写二个解除缓存的按钮,需求利用到wx.clearStorageSync()或wx.clearStorage()方法,前者是壹道通清理地面数据缓存,后者则是异步清理地面数据缓存。当点击那么些按钮的时候就能接触一个点击事件去实践那个清除缓存的不二等秘书籍。

template的路径难题:

我们都知晓template文件中的代码指标是为着给任何页面文件复用的,所以template代码中的所包括的文书路径不要写相对路径,写绝对路径相比较好,因为一旦文件A引用了template文件中的代码,不过文件A和template文件并不是同顶尖的,那么此时如若使用相对路径就会不常常。

相比经典的法门

封装jsonp方法

/**
 * Created by majunchang on 2017/7/23.
 */
import originJsonp from 'jsonp'

// 三个参数粉笔为 目标url 需要拼接在url上的参数 以及jsonp插件 需要的option
export default function jsonp(url,paramdata,options) {
  // 在这里引入一个  拼接字符串的方法
  url += (url.indexOf('?')< 0 ? '?':'&')+param(paramdata);

  // 在这里返回一个Promise对象
  return new Promise((resolve,reject)=>{
    // 在这里的data 跟上面的paramdata是不一样的  一个是 json的返回对象  一个是你传入的参数
    originJsonp(url,options,(err,data)=>{
      if(!err){
        resolve(data)
      }
      else {
        reject(err)
      }
    })
  })
}


function param(paramdata) {
  let url='';
  for(var k in paramdata){
    //  对参数对象里的每一项进行判断
    let value = paramdata[k] ==  undefined ? '': paramdata[k];
    url+= `&${k}=${encodeURIComponent(value)}`
  }
  // 循环结束  url 拼接完毕 将其返回
  return url
}

混乱数组方法

//  此处 添加一个 混乱数组的方法  将一个数组内部的元素 全部打乱
function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min)
}


export function shuffle(arr) {
  var arr1 = arr.slice();
  for (var i = 0; i < arr1.length; i++) {
    var j = getRandomInt(0,i);
    var t = arr1[i];
    arr1[i] = arr1[j];
    arr1[j] = t;
  }
  return arr1
}

动用localstorage存款和储蓄近期喜好的

function insertArr(arr, val, compare, maxLen) {
  var index = arr.findIndex(compare);
  if (index === 0) {
    return
  }
  else if (index > 0) {
    arr.splice(index, 1)
  }
  arr.unshift(val)

  if (maxLen && arr.length > maxLen) {
    arr.pop();
  }
}
function deleteFromArray(arr, compare) {
  const index = arr.findIndex(compare);
  if (index > -1) {
    arr.splice(index, 1);
  }
}

export function saveFavorite(songTarget) {
  let songs = storage.get(favorite_key, []);
  insertArr(songs, songTarget, (item) => {
    return item.id === songTarget.id;
  }, favoriteMaxLen);
  storage.set(favorite_key, songs);
  return songs;
}
export function deleteFavorite(song) {
  let songs = storage.get(favorite_key, [])
  deleteFromArray(songs, (item) => {
    return item.id === song.id
  })
  storage.set(favorite_key, songs)
  return songs
}
export function loadFavorite() {
  return storage.get(favorite_key, []);
}

actions中在原本的歌曲列表中插入1首歌曲的诀要

/*
 声明一个actions  是我们在 suggest的时候  但歌曲列表被检索出来的时候  我们点击歌曲列表 进行播放的事件

 为什么要这样做 因为用户在使用检索的时候 并不希望改变原先的歌曲列表
 我们在播放完  检索的这首歌之后  循环的时候 依然是循环我们原先的播放数组
 */

export const insertSong = function ({commit, state}, song) {
  let playlist = state.playlist.slice()
  let sequencelist = state.sequenceList.slice();
  let currentIndex = state.currentIndex
  // 记录当前歌曲
  // 查找当前播放列表中 是否存在  待插入的歌曲 并返回起索引
  // 因为是插入歌曲 所以索引➕1
  // 插入这首歌 到当前索引的位置
  // 如果包含这首歌
  // 如果插入的序号 大于列表中的序号

  let currentSong = playlist[currentIndex];
  let findPlayIndex = findIndex(playlist, song);
  currentIndex++;
  playlist.splice(currentIndex, 0, song);

  if (findPlayIndex > -1) {
    if (currentIndex > findPlayIndex) {
      playlist.splice(findPlayIndex, 1);
      currentIndex--;
    } else {
      playlist.splice(findPlayIndex + 1, 1);
    }
  }

  let currentSIndex = findIndex(sequencelist, song) + 1;
  let findSeqIndex = findIndex(sequencelist, song);

  sequencelist.splice(currentSIndex, 0, song);
  if (findSeqIndex > -1) {
    if (currentSIndex > findSeqIndex) {
      sequencelist.splice(findSeqIndex, 1);
    } else {
      sequencelist.splice(findSeqIndex + 1, 1);
    }
  }

  commit(types.SET_PLAYLIST, playlist)
  commit(types.SET_SEQUENCE_LIST, sequencelist)
  commit(types.SET_CURRENT_INDEX, currentIndex)
  commit(types.SET_FULL_SCREEN, true)
  commit(types.SET_PLAYING_STATE, true)
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有