Vue学习
- 一、懒加载和axios封装
- 二、Vue工作流
-
- 三、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) {
el.style.display = 'none'
window.onscroll = () => {
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)
http({
url: `/gateway?filmId=${this.$route.params.id}&k=5501344`,
headers: {
'X-Host': 'mall.film-ticket.film.info'
}
}).then((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>
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() {
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) => {
this.cinemaList = res.data.data.cinemas
this.$nextTick(() => {
new BetterScroll('.box', {
scrollbar: {
fade: true
}
})
})
})
},
methods: {
handleLeft() {
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) => {
this.cityList = this.renderCity(res.data.data.cities)
})
},
methods: {
handleChange (data) {
Toast(data)
},
renderCity (list) {
console.log(list)
var cityList = []
var letterList = []
for (var i = 65; i < 91; i++) {
letterList.push(String.fromCharCode(i))
}
letterList.forEach((letter) => {
var newList = list.filter(
(item) => item.pinyin.substring(0, 1).toUpperCase() === letter
)
newList.length > 0 &&
cityList.push({
type: letter,
list: newList
})
})
return cityList
},
handleClick (item) {
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() {
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
}
})
})
}
},
methods: {
handleLeft() {
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) => {
this.cityList = this.renderCity(res.data.data.cities)
})
},
methods: {
handleChange (data) {
Toast(data)
},
renderCity (list) {
console.log(list)
var cityList = []
var letterList = []
for (var i = 65; i < 91; i++) {
letterList.push(String.fromCharCode(i))
}
letterList.forEach((letter) => {
var newList = list.filter(
(item) => item.pinyin.substring(0, 1).toUpperCase() === letter
)
newList.length > 0 &&
cityList.push({
type: letter,
list: newList
})
})
return cityList
},
handleClick (item) {
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 default {
data() {
return {
height: '0px'
}
},
computed: {
a() {
return '1111'
},
...mapState(['cinemaList', 'cityId', 'cityName'])
},
mounted() {
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
}
})
})
}
},
methods: {
...mapActions(['getCinemaData']),
...mapMutations(['clearCinema']),
handleLeft() {
this.$router.push('/city')
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) {
el.style.display = 'none'
window.onscroll = () => {
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() {
http({
url: `/gateway?filmId=${this.$route.params.id}&k=5501344`,
headers: {
'X-Host': 'mall.film-ticket.film.info'
}
}).then((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>