Vue学习:五

Vue学习

  • 一、懒加载和axios封装
  • 二、Vue工作流
    • <1>.同步
    • <2>.异步
  • 三、Vue新写法和持久化

一、懒加载和axios封装

<template>
  <div v-if="filmInfo">
    <detail-header v-scroll="50">
      {{ filmInfo.name }}
    detail-header>
    
    <div
      :style="{
        backgroundImage: 'url(' + filmInfo.poster + ')',
      }"
      class="poster"
    >div>
    <div class="content">
      <div>{{ filmInfo.name }}div>
      <div>
        <div class="detail-text">{{ filmInfo.category }}div>
        <div class="detail-text">
          {{ filmInfo.premiereAt | dateFilter }}上映
        div>
        <div class="detail-text">
          {{ filmInfo.nation }} | {{ filmInfo.runtime }}分钟
        div>
        <div
          class="detail-text"
          style="line-height: 15px"
          :class="isHidden ? 'hidden' : ''"
        >
          {{ filmInfo.synopsis }}
        div>

        <div style="text-align: center">
          <i
            class="iconfont"
            @click="isHidden = !isHidden"
            :class="isHidden ? 'icon-moreunfold' : 'icon-less'"
          >i>
        div>
      div>
      
      <div>
        <div>演职人员div>
        <detail-swiper :perview="3.5" name="actors">
          <detail-swiper-item
            v-for="(data, index) in filmInfo.actors"
            :key="index"
          >
            <div
              :style="{
                backgroundImage: 'url(' + data.avatarAddress + ')',
              }"
              class="avatar"
            >div>
            <div style="text-align: center; font-size: 12px">
              {{ data.name }}
            div>
            <div style="text-align: center; font-size: 13px">
              {{ data.role }}
            div>
          detail-swiper-item>
        detail-swiper>
      div>

      
      <div>
        <div>剧照div>
        <detail-swiper :perview="2" name="photos">
          <detail-swiper-item
            v-for="(data, index) in filmInfo.photos"
            :key="index"
          >
            <div
              :style="{
                backgroundImage: 'url(' + data + ')',
              }"
              class="avatar"
              @click="handlePreview(index)"
            >div>
          detail-swiper-item>
        detail-swiper>
      div>
    div>
  div>
template>
<script>
import http from '@/util/http'
import moment from 'moment'
import Vue from 'vue'
import detailHeader from '@/mycomponents/detail/DetailHeader'
import detailSwiper from '@/mycomponents/detail/DetailSwiper'
import detailSwiperItem from '@/mycomponents/detail/DetailSwiperItem'
import { ImagePreview } from 'vant'

moment.locale('zh-cn') // 设置成中文
Vue.filter('dateFilter', (date) => {
  return moment(date * 1000).format('YYYY-MM-DD')
})

Vue.directive('scroll', {
  inserted (el, binding) {
    // console.log()
    el.style.display = 'none'

    window.onscroll = () => {
      // console.log('scroll')
      if ((document.documentElement.scrollTop || document.body.scrollTop) > binding.value) {
        el.style.display = 'block'
      } else {
        el.style.display = 'none'
      }
    }
  },
  // 销毁执行的
  unbind () {
    window.onscroll = null
  }
})

export default {
  data () {
    return {
      filmInfo: null,
      isHidden: true
    }
  },
  components: {
    detailSwiper,
    detailSwiperItem,
    detailHeader
  },
  methods: {
    handlePreview (index) {
      ImagePreview({
        images: this.filmInfo.photos,
        startPosition: index,
        closeable: true,
        closeIconPosition: 'top-left'
      })
    }
  },
  created () {
    // 当前匹配的路由
    console.log('created', this.$route.params.id)

    // axios 利用 id 发请求到详情接口 ,获取详细数据 ,布局页面

    http({
      url: `/gateway?filmId=${this.$route.params.id}&k=5501344`,
      headers: {
        'X-Host': 'mall.film-ticket.film.info'
      }
    }).then((res) => {
      // console.log(res)
      this.filmInfo = res.data.data.film
    })
  }
}
script>
<style lang="scss" scoped>
.poster {
  width: 100%;
  height: 11.666667rem;
  background-position: center;
  background-size: cover;
}
.content {
  padding: 0.833333rem;
  .detail-text {
    color: #797d82;
    font-size: 13px;
    margin-top: 0.222222rem;
  }
}
.hidden {
  overflow: hidden;
  height: 30px;
}
.avatar {
  width: 100%;
  height: 4.722222rem;
  background-position: center;
  background-size: cover;
}
style>

<template>
    <div>
        <film-swiper :key="datalist.length">
            <film-swiper-item v-for="data in datalist" :key="data.id" class="filmswiperitem">
                <img :src="data.imgUrl"/>
            film-swiper-item>
        film-swiper>
        <film-header class="sticky">film-header>
        <router-view>router-view>
    div>
template>
<script>
// webpack
import filmSwiper from '@/mycomponents/films/FilmSwiper'
import filmHeader from '@/mycomponents/films/FilmHeader'
import filmSwiperItem from '@/mycomponents/films/FilmSwiperItem'
import axios from 'axios'
export default {
  data () {
    return {
      datalist: []
    }
  },
  mounted () {
    axios.get('/banner.json').then(res => {
      console.log(res.data)
      this.datalist = res.data.banner
    })
  },
  components: {
    filmSwiper,
    filmSwiperItem,
    filmHeader
  }
}
script>

<style lang="scss" scoped>
.filmswiperitem{
    img{
        width: 100%;
    }
}
.sticky{
    position: sticky;
    top:0px;
    background:white;
    z-index: 100;
}
style>

二、Vue工作流

<1>.同步

<template>
  <div>
    <van-nav-bar title="影院" ref="navbar" @click-left="handleLeft">
      <template #left>
        {{ $store.state.cityName }}<van-icon name="arrow-down" />
      template>
      <template #right>
        <van-icon name="search" size="28" color="black" />
      template>
    van-nav-bar>

    <div class="box" :style="{
      height: height,
    }">
      <ul>
        <li v-for="data in cinemaList" :key="data.cinemaId">
          <div class="left">
            <div class="cinema_name">{{ data.name }}div>
            <div class="cinema_text">{{ data.address }}div>
          div>

          <div class="right cinema_name">
            <div style="color: red">¥{{ data.lowPrice / 100 }}起div>
          div>
        li>
      ul>
    div>
  div>
template>
<script>
import http from '@/util/http'
import BetterScroll from 'better-scroll'
export default {
  data() {
    return {
      cinemaList: [],
      height: '0px'
    }
  },
  mounted() {
    // console.log(this.$refs.navbar.$el.offsetHeight)
    // 动态结算高度
    this.height =
      document.documentElement.clientHeight -
      this.$refs.navbar.$el.offsetHeight -
      document.querySelector('footer').offsetHeight +
      'px'

    http({
      url: '/gateway?cityId=310100&ticketFlag=1&k=5121167',
      headers: {
        'X-Host': 'mall.film-ticket.cinema.list'
      }
    }).then((res) => {
      //   console.log(res.data.data.cinemas)
      this.cinemaList = res.data.data.cinemas
      //   console.log(document.getElementsByTagName('li').length)

      this.$nextTick(() => {
        new BetterScroll('.box', {
          scrollbar: {
            fade: true
          }
        })
      })
    })
  },
  methods: {
    handleLeft() {
      // console.log('left')
      this.$router.push('/city')
    }
  }
}
script>
<style lang="scss" scoped>
li {
  padding: 0.833333rem;

  display: flex;
  justify-content: space-between;

  .left {
    width: 11.777778rem;
  }

  .cinema_name {
    font-size: 15px;
  }

  .cinema_text {
    color: #797d82;
    font-size: 12px;
    margin-top: 5px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

.box {
  // height: 34.333333rem;
  overflow: hidden;
  position: relative;
  // 修正滚动条的位置
}
style>

<template>
  <div class="city">

    <van-index-bar :index-list="computedList" @select="handleChange">
      <div v-for="data in cityList" :key="data.type">
        <van-index-anchor :index="data.type" />

        <van-cell :title="item.name" v-for="item in data.list" :key="item.cityId" @click="handleClick(item)"/>
      div>
    van-index-bar>
  div>
template>
<script>
import http from '@/util/http'
import { Toast } from 'vant'
export default {
  data () {
    return {
      cityList: []
    }
  },
  computed: {
    computedList () {
      return this.cityList.map(item => item.type)
    }
  },
  mounted () {
    http({
      url: '/gateway?k=5066709',
      headers: {
        'X-Host': 'mall.film-ticket.city.list'
      }
    }).then((res) => {
      //   console.log(res.data.data.cities)
      this.cityList = this.renderCity(res.data.data.cities)
      // 1, 316条 ==> A ,B进行分组
      // 2.  利用转换后的数组,结合组件库进行渲染页面。
    })
  },
  methods: {
    handleChange (data) {
    //   console.log('change', data)
      Toast(data)
    },
    renderCity (list) {
      console.log(list)
      var cityList = []
      var letterList = []
      for (var i = 65; i < 91; i++) {
        // console.log(String.fromCharCode(i))
        letterList.push(String.fromCharCode(i))
      }

      //   console.log(letterList)
      letterList.forEach((letter) => {
        var newList = list.filter(
          (item) => item.pinyin.substring(0, 1).toUpperCase() === letter
        )
        // console.log(newList)

        newList.length > 0 &&
          cityList.push({
            type: letter,
            list: newList
          })
      })

      //   console.log(cityList)
      return cityList
    },
    handleClick (item) {
    //   console.log(item.name, item.cityId)

      // 传统的多页面方案
      //  1. location.href = '#/cinemas?cityname=' + item.name
      //  2. cookie , localStorage

      // 单页面方案,
      //  1. 中间人模式
      //  2. bus事件总线 $on ,$emit

      // vuex- 状态管理模式

      //   console.log()
      //   this.$store.state.cityName = item.name //

      this.$store.commit('changeCityName', item.name)
      this.$router.back()
    }
  }
}
script>
<style lang="scss" >
.van-toast--html, .van-toast--text{
    min-width: 30px;
}
style>

<2>.异步

<template>
  <div>
    <van-nav-bar title="影院" ref="navbar" @click-left="handleLeft" @click-right="handleRight">
      <template #left>
        {{ $store.state.cityName }}<van-icon name="arrow-down" />
      template>
      <template #right>
        <van-icon name="search" size="28" color="black" />
      template>
    van-nav-bar>

    <div class="box" :style="{
      height: height,
    }">
      <ul>
        <li v-for="data in $store.state.cinemaList" :key="data.cinemaId">
          <div class="left">
            <div class="cinema_name">{{ data.name }}div>
            <div class="cinema_text">{{ data.address }}div>
          div>

          <div class="right cinema_name">
            <div style="color: red">¥{{ data.lowPrice / 100 }}起div>
          div>
        li>
      ul>
    div>
  div>
template>
<script>
import BetterScroll from 'better-scroll'
export default {
  data() {
    return {
      height: '0px'
    }
  },
  mounted() {
    // console.log(this.$refs.navbar.$el.offsetHeight)
    // 动态结算高度
    this.height =
      document.documentElement.clientHeight -
      this.$refs.navbar.$el.offsetHeight -
      document.querySelector('footer').offsetHeight +
      'px'

    // 分发

    if (this.$store.state.cinemaList.length === 0) {
      this.$store.dispatch('getCinemaData', this.$store.state.cityId).then(res => {
        this.$nextTick(() => {
          new BetterScroll('.box', {
            scrollbar: {
              fade: true
            }
          })
        })
      })
    } else {
      console.log('缓存')
      this.$nextTick(() => {
        new BetterScroll('.box', {
          scrollbar: {
            fade: true
          }
        })
      })
    }

    // http({
    //   url: `/gateway?cityId=${this.$store.state.cityId}&ticketFlag=1&k=5121167`,
    //   headers: {
    //     'X-Host': 'mall.film-ticket.cinema.list'
    //   }
    // }).then((res) => {
    //   //   console.log(res.data.data.cinemas)
    //   this.cinemaList = res.data.data.cinemas
    //   //   console.log(document.getElementsByTagName('li').length)

    //   this.$nextTick(() => {
    //     new BetterScroll('.box', {
    //       scrollbar: {
    //         fade: true
    //       }
    //     })
    //   })
    // })
  },
  methods: {
    handleLeft() {
      // console.log('left')
      this.$router.push('/city')
    },
    handleRight() {
      this.$router.push('/cinemas/search')
    }
  }
}
script>
<style lang="scss" scoped>
li {
  padding: 0.833333rem;

  display: flex;
  justify-content: space-between;

  .left {
    width: 11.777778rem;
  }

  .cinema_name {
    font-size: 15px;
  }

  .cinema_text {
    color: #797d82;
    font-size: 12px;
    margin-top: 5px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

.box {
  // height: 34.333333rem;
  overflow: hidden;
  position: relative;
  // 修正滚动条的位置
}
style>

<template>
  <div class="city">

    <van-index-bar :index-list="computedList" @select="handleChange">
      <div v-for="data in cityList" :key="data.type">
        <van-index-anchor :index="data.type" />

        <van-cell :title="item.name" v-for="item in data.list" :key="item.cityId" @click="handleClick(item)"/>
      div>
    van-index-bar>
  div>
template>
<script>
import http from '@/util/http'
import { Toast } from 'vant'
export default {
  data () {
    return {
      cityList: []
    }
  },
  computed: {
    computedList () {
      return this.cityList.map(item => item.type)
    }
  },
  mounted () {
    http({
      url: '/gateway?k=5066709',
      headers: {
        'X-Host': 'mall.film-ticket.city.list'
      }
    }).then((res) => {
      //   console.log(res.data.data.cities)
      this.cityList = this.renderCity(res.data.data.cities)
      // 1, 316条 ==> A ,B进行分组
      // 2.  利用转换后的数组,结合组件库进行渲染页面。
    })
  },
  methods: {
    handleChange (data) {
    //   console.log('change', data)
      Toast(data)
    },
    renderCity (list) {
      console.log(list)
      var cityList = []
      var letterList = []
      for (var i = 65; i < 91; i++) {
        // console.log(String.fromCharCode(i))
        letterList.push(String.fromCharCode(i))
      }

      //   console.log(letterList)
      letterList.forEach((letter) => {
        var newList = list.filter(
          (item) => item.pinyin.substring(0, 1).toUpperCase() === letter
        )
        // console.log(newList)

        newList.length > 0 &&
          cityList.push({
            type: letter,
            list: newList
          })
      })

      //   console.log(cityList)
      return cityList
    },
    handleClick (item) {
    //   console.log(item.name, item.cityId)

      // 传统的多页面方案
      //  1. location.href = '#/cinemas?cityname=' + item.name
      //  2. cookie , localStorage

      // 单页面方案,
      //  1. 中间人模式
      //  2. bus事件总线 $on ,$emit

      // vuex- 状态管理模式

      //   console.log()
      //   this.$store.state.cityName = item.name //

      this.$store.commit('changeCityName', item.name)
      this.$store.commit('changeCityId', item.cityId)
      this.$router.back()
    }
  }
}
script>
<style lang="scss" >
.van-toast--html, .van-toast--text{
    min-width: 30px;
}
style>

三、Vue新写法和持久化

<template>
  <div>
    <van-nav-bar title="影院" ref="navbar" @click-left="handleLeft" @click-right="handleRight">
      <template #left>
        {{ cityName }}<van-icon name="arrow-down" />
      template>
      <template #right>
        <van-icon name="search" size="28" color="black" />
      template>
    van-nav-bar>

    <div class="box" :style="{
      height: height,
    }">
      <ul>
        <li v-for="data in cinemaList" :key="data.cinemaId">
          <div class="left">
            <div class="cinema_name">{{ data.name }}div>
            <div class="cinema_text">{{ data.address }}div>
          div>

          <div class="right cinema_name">
            <div style="color: red">¥{{ data.lowPrice / 100 }}起div>
          div>
        li>
      ul>
    div>
  div>
template>
<script>
import BetterScroll from 'better-scroll'
import { mapState, mapActions, mapMutations } from 'vuex' // export {mapState}
// console.log(mapState(['cinemaList']))
export default {
  data() {
    return {
      height: '0px'
    }
  },
  computed: {
    a() {
      return '1111'
    },
    ...mapState(['cinemaList', 'cityId', 'cityName'])
  },

  mounted() {
    // console.log(this.$refs.navbar.$el.offsetHeight)
    // 动态结算高度
    this.height =
      document.documentElement.clientHeight -
      this.$refs.navbar.$el.offsetHeight -
      document.querySelector('footer').offsetHeight +
      'px'

    // 分发

    if (this.cinemaList.length === 0) {
      this.getCinemaData(this.cityId).then(res => {
        this.$nextTick(() => {
          new BetterScroll('.box', {
            scrollbar: {
              fade: true
            }
          })
        })
      })
    } else {
      console.log('缓存')
      this.$nextTick(() => {
        new BetterScroll('.box', {
          scrollbar: {
            fade: true
          }
        })
      })
    }

    // http({
    //   url: `/gateway?cityId=${this.$store.state.cityId}&ticketFlag=1&k=5121167`,
    //   headers: {
    //     'X-Host': 'mall.film-ticket.cinema.list'
    //   }
    // }).then((res) => {
    //   //   console.log(res.data.data.cinemas)
    //   this.cinemaList = res.data.data.cinemas
    //   //   console.log(document.getElementsByTagName('li').length)

    //   this.$nextTick(() => {
    //     new BetterScroll('.box', {
    //       scrollbar: {
    //         fade: true
    //       }
    //     })
    //   })
    // })
  },
  methods: {
    ...mapActions(['getCinemaData']),
    ...mapMutations(['clearCinema']),
    handleLeft() {
      // console.log('left')
      this.$router.push('/city')

      // 清空cinemaList
      this.clearCinema()
    },
    handleRight() {
      this.$router.push('/cinemas/search')
    }
  }
}
script>
<style lang="scss" scoped>
li {
  padding: 0.833333rem;

  display: flex;
  justify-content: space-between;

  .left {
    width: 11.777778rem;
  }

  .cinema_name {
    font-size: 15px;
  }

  .cinema_text {
    color: #797d82;
    font-size: 12px;
    margin-top: 5px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

.box {
  // height: 34.333333rem;
  overflow: hidden;
  position: relative;
  // 修正滚动条的位置
}
style>

<template>
  <div v-if="filmInfo">
    <detail-header v-scroll="50">
      {{ filmInfo.name }}
    detail-header>
    
    <div :style="{
      backgroundImage: 'url(' + filmInfo.poster + ')',
    }" class="poster">div>
    <div class="content">
      <div>{{ filmInfo.name }}div>
      <div>
        <div class="detail-text">{{ filmInfo.category }}div>
        <div class="detail-text">
          {{ filmInfo.premiereAt | dateFilter }}上映
        div>
        <div class="detail-text">
          {{ filmInfo.nation }} | {{ filmInfo.runtime }}分钟
        div>
        <div class="detail-text" style="line-height: 15px" :class="isHidden ? 'hidden' : ''">
          {{ filmInfo.synopsis }}
        div>

        <div style="text-align: center">
          <i class="iconfont" @click="isHidden = !isHidden" :class="isHidden ? 'icon-moreunfold' : 'icon-less'">i>
        div>
      div>
      
      <div>
        <div>演职人员div>
        <detail-swiper :perview="3.5" name="actors">
          <detail-swiper-item v-for="(data, index) in filmInfo.actors" :key="index">
            <div :style="{
              backgroundImage: 'url(' + data.avatarAddress + ')',
            }" class="avatar">div>
            <div style="text-align: center; font-size: 12px">
              {{ data.name }}
            div>
            <div style="text-align: center; font-size: 13px">
              {{ data.role }}
            div>
          detail-swiper-item>
        detail-swiper>
      div>

      
      <div>
        <div>剧照div>
        <detail-swiper :perview="2" name="photos">
          <detail-swiper-item v-for="(data, index) in filmInfo.photos" :key="index">
            <div :style="{
              backgroundImage: 'url(' + data + ')',
            }" class="avatar" @click="handlePreview(index)">div>
          detail-swiper-item>
        detail-swiper>
      div>
    div>
  div>
template>
<script>
import http from '@/util/http'
import obj from '@/util/mixinObj'
import moment from 'moment'
import Vue from 'vue'
import detailHeader from '@/mycomponents/detail/DetailHeader'
import detailSwiper from '@/mycomponents/detail/DetailSwiper'
import detailSwiperItem from '@/mycomponents/detail/DetailSwiperItem'
import { ImagePreview } from 'vant'

moment.locale('zh-cn') // 设置成中文
Vue.filter('dateFilter', (date) => {
  return moment(date * 1000).format('YYYY-MM-DD')
})

Vue.directive('scroll', {
  inserted(el, binding) {
    // console.log()
    el.style.display = 'none'

    window.onscroll = () => {
      // console.log('scroll')
      if ((document.documentElement.scrollTop || document.body.scrollTop) > binding.value) {
        el.style.display = 'block'
      } else {
        el.style.display = 'none'
      }
    }
  },
  // 销毁执行的
  unbind() {
    window.onscroll = null
  }
})

export default {
  mixins: [obj],
  data() {
    return {
      filmInfo: null,
      isHidden: true
    }
  },
  components: {
    detailSwiper,
    detailSwiperItem,
    detailHeader
  },
  methods: {
    handlePreview(index) {
      ImagePreview({
        images: this.filmInfo.photos,
        startPosition: index,
        closeable: true,
        closeIconPosition: 'top-left'
      })
    }
  },
  mounted() {
    // 当前匹配的路由
    // console.log('created', this.$route.params.id)

    // axios 利用 id 发请求到详情接口 ,获取详细数据 ,布局页面

    http({
      url: `/gateway?filmId=${this.$route.params.id}&k=5501344`,
      headers: {
        'X-Host': 'mall.film-ticket.film.info'
      }
    }).then((res) => {
      // console.log(res)
      this.filmInfo = res.data.data.film
    })
  }
}
script>
<style lang="scss" scoped>
.poster {
  width: 100%;
  height: 11.666667rem;
  background-position: center;
  background-size: cover;
}

.content {
  padding: 0.833333rem;

  .detail-text {
    color: #797d82;
    font-size: 13px;
    margin-top: 0.222222rem;
  }
}

.hidden {
  overflow: hidden;
  height: 30px;
}

.avatar {
  width: 100%;
  height: 4.722222rem;
  background-position: center;
  background-size: cover;
}
style>

你可能感兴趣的:(vue.js,学习,javascript)