首先来看一下网站效果,想写这个项目的读者可以自行下载哦,地址:https://github.com/Stray-Kite/Car

在这个项目中,我们主要是为了学习语种切换,也就是右上角的 中文/English 功能的实现。

首先看一下模拟的后台数据src/config/modules/lang.js 文件中:

关键代码:

 export default {
name: 'Homepage',
components: {
ScrollNumber
},
data () {
return {
lang: 'chinese',
pageIndex: 0,
stepIndex: 0
}
},
......其余代码 methods: {
addClass (el, _class) { //切换语言
toggleLang (lang) {
this.lang = lang
// this.animatePage()
}
},
//以下几个computed是获取config文件夹里的数据
computed: {
langs () {
return config.langs[this.lang] //主要靠这里切换,这个切换的本质其实就是使用了另一套英文的数据(换了一套后台数据)
},
......其余代码 }
}

最后给大家一波儿带注解的代码,方便理解:

Homepage.vue(CSS我就不给啦,因为这东西看着学一下就好):

 <template>
<div class="container"> <div class="rc-header">
<!--首先这是两个切换语言的按钮(中文/English)-->
<div class="rc-header-right">
<a href="#" :class="{'is-active': this.lang === 'chinese'}" @click="toggleLang('chinese')">中文</a>&nbsp;/
<a href="#" :class="{'is-active': this.lang === 'english'}" @click="toggleLang('english')">English</a>
</div>
<!--顶栏其他的元素,图片等...-->
<div class="rc-header-left">
<img class="rc-logo" :src="media.LOGO_PATH">
<img class="rc-slogan" :src="media.SLOGAN_PATH">
</div>
</div> <!--下面就是整个内容页了,大的来说这四页就是一个大的竖着的轮播图,用了vue的swiper-->
<div class="swiper-container rc-body">
<div class="swiper-wrapper"> <!--第一页-->
<div class="swiper-slide">
<div class="rc-page rc-page01">
<!--星空和车-->
<div class="rc-galaxy">
<div class="rc-bg rc-layer-bg" ref="plbo"
:style="{backgroundImage: 'url(' + common.GALAXY_LAYER_BG + ')', top: layerEdge, bottom: layerEdge, left: layerEdge, right: layerEdge}">
</div>
<div class="rc-bg rc-layer-top" ref="plto"
:style="{backgroundImage: 'url(' + common.GALAXY_LAYER_TOP + ')'}">
</div>
</div> <div class="rc-content-wrapper">
<!--若是第一页,即index=0,则显示,否则隐藏-->
<div class="rc-text-wrapper" ref="ptwo"
:style="{visibility: pageIndex === 0 ? 'visible' : 'hidden'}" >
<h2>{{langs.PAGE_ONE_SLOGAN}}</h2>
<!--scroll-number是数字增加,引入widgets/ScrollNumber.vue的方法-->
<scroll-number :size="isMobile ? 18 : 24" ref="psno">
<span slot="suffix" style="color: #c3c3c3;">{{langs.PAGE_ONE_SUB_SLOGAN}}</span>
</scroll-number>
</div>
<button class="btn btn-success btn-try"
:style="{visibility: pageIndex === 0 ? 'visible' : 'hidden'}"
ref="pbro">{{langs.TRY_LABEL}}</button>
</div> <!--下面这两个img不用管,已经隐藏啦-->
<img :src="common.GALAXY_REAL_TOP" v-show="false">
<img :src="common.GALAXY_REAL_BG" v-show="false">
</div>
</div> <!--第二页-->
<div class="swiper-slide">
<div class="rc-page rc-page02">
<div class="rc-content-wrapper">
<div
class="rc-text-wrapper"
:style="{visibility: pageIndex === 1 ? 'visible' : 'hidden'}"
ref="ptwt">
<h2>{{langs.PAGE_TWO_SLOGAN}}</h2>
</div>
<div class="rc-step-wrapper">
<div class="rc-step-stage">
<div class="swiper-container rc-step-container">
<div class="swiper-wrapper">
<div
v-for="(step, index) in langs.STEPS_PROFILE"
:key="index"
class="swiper-slide rc-step">
<div class="rc-step-content">
<h2 class="rc-step-title">{{langs.STEP_LABEL}} {{index + 1}}</h2>
<p class="rc-step-profile">{{step}}</p>
<button
class="btn"
ref="pbdt"
v-if="index === 0">{{langs.DOWNLOAD_LABEL}}</button>
<button
class="btn"
ref="pbat"
v-if="index === 1">{{langs.AUTH_LABEL}}</button>
</div>
</div>
</div>
<div class="swiper-scrollbar"></div>
<div class="swiper-button-next" v-if="!isMobile"></div>
<div class="swiper-button-prev" v-if="!isMobile"></div>
</div>
</div>
<!--步骤右面的图片-->
<div class="rc-step-scene" v-if="!isMobile">
<div
:style="{backgroundImage: 'url(' + media.STEPS_ACTOR_PATH[stepIndex] + ')'}"
class="rc-bg rc-step-actor"></div>
</div>
</div>
</div>
</div>
</div> <!--第三页-->
<div class="swiper-slide">
<div class="rc-page rc-page03">
<div class="rc-content-wrapper">
<div
class="rc-text-wrapper"
:style="{visibility: pageIndex === 2 ? 'visible' : 'hidden'}"
ref="ptwth">
<h2>{{langs.PAGE_THREE_SLOGAN}}</h2>
</div>
<div class="rc-cars-gallery">
<div
v-for="(car, index) in langs.CARS_PROFILE"
:key="index"
class="rc-car">
<div class="rc-car-card" :title="langs.CARS_TOOLTIP">
<div class="rc-car-media">
<div
:style="{backgroundImage: 'url(' + common.CARS_PATH[index] + ')'}"
class="rc-bg rc-bg-scale rc-car-snapshot"></div>
</div>
<div class="rc-car-profile">
<h4>{{car.NAME}}</h4>
<div>{{langs.OWNER_LABEL}}:&nbsp;{{car.OWNER}}</div>
<div>{{langs.DATE_LABEL}}:&nbsp;{{car.DATE}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div> <!--第四页-->
<div class="swiper-slide">
<div class="rc-page rc-page04">
<div
class="rc-text-wrapper"
:style="{visibility: pageIndex === 3 ? 'visible' : 'hidden'}"
ref="ptwf">
<h2>{{langs.PAGE_FOUR_SLOGAN}}</h2>
</div>
<div class="rc-content-wrapper">
<div class="rc-bg rc-drive-stage">
<div
:style="{backgroundImage: 'url(' + common.DRIVE_STAGE_ACTOR + ')'}"
class="rc-bg rc-actor-car" ref="pdcf"></div>
</div>
</div>
</div>
</div>
</div>
<div class="swiper-pagination" v-show="!isMobile"></div>
</div>
</div>
</template> <script>
/* eslint-disable */
import Swiper from 'swiper'
import 'swiper/dist/css/swiper.min.css'
import 'animate.css/animate.min.css'
import config from '../config'
import ScrollNumber from '@/widgets/ScrollNumber.vue'
export default {
name: 'Homepage',
components: {
ScrollNumber
},
data () {
return {
lang: 'chinese',
pageIndex: 0,
stepIndex: 0
}
},
beforeCreate () {
/**
* 旋转星空
* step 3: 计算可视区域对角线, 根据对角线长度撑开容器
*/
let w = document.body.clientWidth
let h = document.body.clientHeight
this.layerEdge = 'calc(50% - ' + Math.ceil(Math.sqrt(w * w + h * h) / 2) + 'px)'
},
mounted () {
this.$nextTick(function () {
let _self = this
/* eslint-disable no-new */
new Swiper('.rc-body', {
speed: 800,
direction: 'vertical',
paginationClickable: true,
mousewheel: true,
pagination: {
el: '.swiper-pagination'
},
on: {
slideChangeTransitionEnd () {
_self.pageIndex = this.activeIndex
_self.animatePage()
}
}
})
this.initPage()
})
},
methods: {
addClass (el, _class) {
let elClassArr = el.className.split(' ') //用单个空格分割
let classArr = _class.split(' ') //同上
classArr.forEach(item => {
// 如果elClassArr中没有这个元素(类型),那么添加进去
if (elClassArr.indexOf(item) === -1) {
elClassArr.push(String(item))
}
})
//添加完后本属性后面要有一个空格隔开
el.className = elClassArr.join(' ')
return el
},
removeClass (el, _class) {
let elClassArr = el.className.split(' ')
let classArr = _class.split(' ')
classArr.forEach(item => {
let index = elClassArr.indexOf(item)
if (index > -1) {
elClassArr.splice(index, 1)
}
})
el.className = elClassArr.join(' ')
return el
},
bindAnimation (el, x) {
let _self = this
// 监听动画结束事件
let events = [
'webkitAnimationEnd',
'mozAnimationEnd',
'MSAnimationEnd',
'oanimationend',
'animationend'
]
_self.addClass(el, x + ' animated')
events.forEach(event => {
let func = function () {
events.forEach(item => {
el.removeEventListener(item, func)
})
_self.removeClass(el, x + ' animated')
}
//增加事件监听,如果时间结束,那么再利用fun函数移除监听的事件和添加进来的新类(class属性)
el.addEventListener(event, func)
})
},
initPage01 () {
setTimeout(() => {
/**
* 旋转星空
* step 4: 采用真实图片替换代理图片
*/
this.$refs.plto.style.backgroundImage = 'url(' + this.common.GALAXY_REAL_TOP + ')'
this.$refs.plbo.style.backgroundImage = 'url(' + this.common.GALAXY_REAL_BG + ')'
}, 2000)
this.animatePage01() //动画效果(数字上升)
},
//第二页
initPage02 () {
let _self = this
let pbdt = this.$refs.pbdt[0]
let pbat = this.$refs.pbat[0]
let bindAnimation = this.bindAnimation
new Swiper('.rc-step-container', {
speed: 600,
scrollbar: {
el: '.swiper-scrollbar',
draggable: true
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev'
},
on: {
slideChangeTransitionEnd () {
if (this.activeIndex === 0) {
bindAnimation(pbdt, 'tada')
} else if (this.activeIndex === 1) {
bindAnimation(pbat, 'tada')
}
_self.stepIndex = this.activeIndex
}
}
})
},
initPage03 () {},
initPage04 () {}, //初始化四个界面方法
initPage () {
this.initPage01()
this.initPage02()
this.initPage03()
this.initPage04()
}, animatePage01 () {
this.bindAnimation(this.$refs.ptwo, 'fadeIn')
this.bindAnimation(this.$refs.pbro, 'fadeIn')
this.$refs.psno.$emit('start')
},
animatePage02 () {
this.bindAnimation(this.$refs.ptwt, 'fadeInDown')
},
animatePage03 () {
this.bindAnimation(this.$refs.ptwth, 'flipInY')
},
animatePage04 () {
this.bindAnimation(this.$refs.ptwf, 'jackInTheBox')
setTimeout(() => {
this.bindAnimation(this.$refs.pdcf, 'rc-arrive')
}, 600)
},
// QA: 函数本是对象
animatePage (index) {
[
this.animatePage01,
this.animatePage02,
this.animatePage03,
this.animatePage04
][index || this.pageIndex]()
},
//切换语言
toggleLang (lang) {
this.lang = lang
// this.animatePage()
}
},
//以下几个computed是获取config文件夹里的数据
computed: {
langs () {
return config.langs[this.lang]
},
media () {
return config.media[this.lang]
},
common () {
return config.common
},
// 判断移动端,无需记住,会用就好,返回值为bool值
isMobile () {
return 这个就不给了,这个直接用就好了 }
}
}
</script> <style scoped>
</style>

widgets/ScrollNumber.vue(数字增长):

 <template>
<div class="scroll-number" :style="{fontSize: size + 'px'}">
<slot name="prefix"></slot>
<span class="number">{{value}}</span>
<slot name="suffix"></slot>
</div>
</template> <script>
import TWEEN from 'tween.js'
export default {
name: 'ScrollNumber',
data () {
return {
value: 0,
animation: null
}
},
props: {
total: {
type: Number,
default: 15374
},
size: {
type: Number,
default: 24
}
},
mounted () {
this.$nextTick(function () {
const animate = function (time) {
requestAnimationFrame(animate)
TWEEN.update(time)
}
requestAnimationFrame(animate)
let _self = this
// 增长起始值,从0开始
let surface = {value: 0}
// 增加从0增长到total动画1600为时间
this.animation = new TWEEN.Tween(surface).to({value: _self.total}, 1600)
this.animation.easing(TWEEN.Easing.Exponential.Out).onUpdate(() => {
_self.value = Math.floor(surface.value)
})
// 监听父组件通讯事件
this.$on('start', () => {
surface.value = 0
this.animation.start()
})
})
}
}
</script> <style scoped>
.number {
display: inline-block;
min-width: 40px;
color: orangered;
text-align: center;
font-weight: 600;
}
</style>

注:其中TWEEN的用法我找到了一篇比较不错的文章,地址:https://www.jianshu.com/p/164538a89939

Vue.js项目实战-多语种网站(租车)的更多相关文章

  1. 第10章-Vue.js 项目实战

    一.本节内容 掌握项目环境中路由的配置方法 ***** 熟练掌握编写单文件组件的编写 *** 能够使用swiper.js进行轮播图组件的封装 能够使用axios进行数据请求 二.webpack项目的目 ...

  2. Vue.js项目实战-打造线上商城

    首先上一下完成后的效果: 首页: 商品详情页: 购物车页(其实还有个订单页,只是和购物车页基本类似,所以就不截图啦): 开始项目: 由于涉及的是前后端分离,所以我们的后台数据就模拟存储于浏览器端(co ...

  3. 新书上线:《Spring Boot+Spring Cloud+Vue+Element项目实战:手把手教你开发权限管理系统》,欢迎大家买回去垫椅子垫桌脚

    新书上线 大家好,笔者的新书<Spring Boot+Spring Cloud+Vue+Element项目实战:手把手教你开发权限管理系统>已上线,此书内容充实.材质优良,乃家中必备垫桌脚 ...

  4. Vuejs实例-01使用vue-cli脚手架搭建Vue.js项目

    [TOC] 1. 前言 vue-cli 一个简单的构建Vue.js项目的命令行界面 整体过程: $ npm install -g vue-cli $ vue init webpack vue-admi ...

  5. vue.js项目构建

    这里构建的vue.js项目依赖node服务器运行. 项目搭建完整步骤: 安装node.js ,转至nodeJs网站http://nodejs.cn/ 下载nodeJs进行安装. 安装完毕检查nodeJ ...

  6. 【Vue.js游戏机实战】- Vue.js实现九宫格水果机抽奖游戏总结

    大家好!先上图看看本次案例的整体效果. 完整版实战课程附源码:[Vue.js游戏机实战]- Vue.js实现九宫格水果机抽奖 实现思路: Vue component实现九宫格水果机组件,可以嵌套到任意 ...

  7. 【Vue.js游戏机实战】- Vue.js实现老虎-机抽奖总结

    大家好!先上图看看本次案例的整体效果. 完整版实战课程附源码:[Vue.js游戏机实战]- Vue.js实现老虎-机抽奖 实现思路: Vue component实现老虎-机组件,可以嵌套到任意要使用的 ...

  8. 如何将你的 Vue.js 项目部署在云开发静态托管之上

    云开发静态托管是云开发提供的静态网站托管的能力,静态资源(HTML.CSS.JavaScript.字体等)的分发由腾讯云对象存储 COS 和拥有多个边缘网点的腾讯云 CDN 提供支持. 在云开发静态托 ...

  9. vue.js项目安装

    Vue.js 安装 NPM 方法安装vue.js项目 npm 版本需要大于 3.0,如果低于此版本需要升级它: # 查看版本 $ npm -v 2.3.0 #升级 npm npm install np ...

随机推荐

  1. JavaScript 正则表达式 初探

    JavaScript 正则表达式 正则表达式是构成搜索模式的字符序列 搜索模式可用于文本搜索和文本替换操作 使用正则 字符串方法 在JavaScript中,正则表达式常常用两个字符串方法: searc ...

  2. DS12C887实时时钟

    实物图 引脚定义 GND. VCC:直流电源,其中VCC接+5V输入,GND接地,当VCC输入为+5V时,用户可以访问DS12C887内RAM中的数据,并可对其进行读.写操作:当VCC的输入小于+4. ...

  3. 移动OA办公——Smobiler第一个开源应用解决方案,快来get吧

    产品简介 SmoONE是一款移动OA类的开源解决方案,通过Smobiler平台开发,包含了注册.登陆.用户信息等基本功能.集成了OA中使用场景较多的报销.请假.部门管理.成本中心等核心功能. 免费获取 ...

  4. 软工个人项目(Java实现)

    一. Github地址: https://github.com/RuiBingo/PersonalWork 二.个人PSP表格: PSP2.1 PSP阶段 预估耗时(分钟) 实际耗时(分钟) Plan ...

  5. MySQL 部署分布式架构 MyCAT (一)

    架构 环境 主机名 IP db1 192.168.31.205 db2 192.168.31.206 前期准备 开启防火墙,安装配置 mysql (db1,db2) firewall-cmd --pe ...

  6. [Go] 使用go mod安装beego

    需要go升级到1.12或以上 mkdir gomodtest cd gomodtest go mod init gomodtest 创建一个server.go package main import ...

  7. CentOS7设置开机自启动方式

    方式一: # 在/etc/rc.d/rc.local文件中追加启动命令,该文件追加后,会随着机器自动后,自动运行文件中的命令 # vim /etc/rc.d/rc.local # 权限问题:在cent ...

  8. 【洛谷P4148】简单题(kd-tree)

    传送门 题意: 给出一个\(n*n\)的棋盘,现在有两种操作:一种是某个格子里的数字加上\(A\),另一种是询问矩阵和. 空间限制:\(20MB\),强制在线. 思路: 直接\(kd-tree\)来搞 ...

  9. Html学习之十八(表格与表单学习--统计表制作)

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  10. C++ class内的==重载,判断相等,测试等于,重载示例。二元操作符

    #include <iostream> // overloading "operator == " inside class // == 是二元操作符 //////// ...