Vue.js项目实战-多语种网站(租车)
首先来看一下网站效果,想写这个项目的读者可以自行下载哦,地址:https://github.com/Stray-Kite/Car:
在这个项目中,我们主要是为了学习语种切换,也就是右上角的 中文/English 功能的实现。
首先看一下模拟的后台数据src/config/modules/lang.js 文件中:
关键代码:
1 export default {2 name: \'Homepage\',
3 components: {
4 ScrollNumber
5 },
6 data () {
7 return {
8 lang: \'chinese\',
9 pageIndex: 0,
10 stepIndex: 0
11 }
12 },
13 ......其余代码 44 methods: {
45 addClass (el, _class) {177 //切换语言
178 toggleLang (lang) {
179 this.lang = lang
180 // this.animatePage()
181 }
182 },
183 //以下几个computed是获取config文件夹里的数据
184 computed: {
185 langs () {
186 return config.langs[this.lang] //主要靠这里切换,这个切换的本质其实就是使用了另一套英文的数据(换了一套后台数据)
187 },
188 ......其余代码198 }
199 }
最后给大家一波儿带注解的代码,方便理解:
Homepage.vue(CSS我就不给啦,因为这东西看着学一下就好):
1 <template>2 <div class="container">
3
4
5 <div class="rc-header">
6 <!--首先这是两个切换语言的按钮(中文/English)-->
7 <div class="rc-header-right">
8 <a href="#" :class="{\'is-active\': this.lang === \'chinese\'}" @click="toggleLang(\'chinese\')">中文</a> /
9 <a href="#" :class="{\'is-active\': this.lang === \'english\'}" @click="toggleLang(\'english\')">English</a>
10 </div>
11 <!--顶栏其他的元素,图片等...-->
12 <div class="rc-header-left">
13 <img class="rc-logo" :src="media.LOGO_PATH">
14 <img class="rc-slogan" :src="media.SLOGAN_PATH">
15 </div>
16 </div>
17
18 <!--下面就是整个内容页了,大的来说这四页就是一个大的竖着的轮播图,用了vue的swiper-->
19 <div class="swiper-container rc-body">
20 <div class="swiper-wrapper">
21
22 <!--第一页-->
23 <div class="swiper-slide">
24 <div class="rc-page rc-page01">
25 <!--星空和车-->
26 <div class="rc-galaxy">
27 <div class="rc-bg rc-layer-bg" ref="plbo"
28 :style="{backgroundImage: \'url(\' + common.GALAXY_LAYER_BG + \')\', top: layerEdge, bottom: layerEdge, left: layerEdge, right: layerEdge}">
29 </div>
30 <div class="rc-bg rc-layer-top" ref="plto"
31 :style="{backgroundImage: \'url(\' + common.GALAXY_LAYER_TOP + \')\'}">
32 </div>
33 </div>
34
35 <div class="rc-content-wrapper">
36 <!--若是第一页,即index=0,则显示,否则隐藏-->
37 <div class="rc-text-wrapper" ref="ptwo"
38 :style="{visibility: pageIndex === 0 ? \'visible\' : \'hidden\'}" >
39 <h2>{{langs.PAGE_ONE_SLOGAN}}</h2>
40 <!--scroll-number是数字增加,引入widgets/ScrollNumber.vue的方法-->
41 <scroll-number :size="isMobile ? 18 : 24" ref="psno">
42 <span slot="suffix" style="color: #c3c3c3;">{{langs.PAGE_ONE_SUB_SLOGAN}}</span>
43 </scroll-number>
44 </div>
45 <button class="btn btn-success btn-try"
46 :style="{visibility: pageIndex === 0 ? \'visible\' : \'hidden\'}"
47 ref="pbro">{{langs.TRY_LABEL}}</button>
48 </div>
49
50 <!--下面这两个img不用管,已经隐藏啦-->
51 <img :src="common.GALAXY_REAL_TOP" v-show="false">
52 <img :src="common.GALAXY_REAL_BG" v-show="false">
53 </div>
54 </div>
55
56 <!--第二页-->
57 <div class="swiper-slide">
58 <div class="rc-page rc-page02">
59 <div class="rc-content-wrapper">
60 <div
61 class="rc-text-wrapper"
62 :style="{visibility: pageIndex === 1 ? \'visible\' : \'hidden\'}"
63 ref="ptwt">
64 <h2>{{langs.PAGE_TWO_SLOGAN}}</h2>
65 </div>
66 <div class="rc-step-wrapper">
67 <div class="rc-step-stage">
68 <div class="swiper-container rc-step-container">
69 <div class="swiper-wrapper">
70 <div
71 v-for="(step, index) in langs.STEPS_PROFILE"
72 :key="index"
73 class="swiper-slide rc-step">
74 <div class="rc-step-content">
75 <h2 class="rc-step-title">{{langs.STEP_LABEL}} {{index + 1}}</h2>
76 <p class="rc-step-profile">{{step}}</p>
77 <button
78 class="btn"
79 ref="pbdt"
80 v-if="index === 0">{{langs.DOWNLOAD_LABEL}}</button>
81 <button
82 class="btn"
83 ref="pbat"
84 v-if="index === 1">{{langs.AUTH_LABEL}}</button>
85 </div>
86 </div>
87 </div>
88 <div class="swiper-scrollbar"></div>
89 <div class="swiper-button-next" v-if="!isMobile"></div>
90 <div class="swiper-button-prev" v-if="!isMobile"></div>
91 </div>
92 </div>
93 <!--步骤右面的图片-->
94 <div class="rc-step-scene" v-if="!isMobile">
95 <div
96 :style="{backgroundImage: \'url(\' + media.STEPS_ACTOR_PATH[stepIndex] + \')\'}"
97 class="rc-bg rc-step-actor"></div>
98 </div>
99 </div>
100 </div>
101 </div>
102 </div>
103
104 <!--第三页-->
105 <div class="swiper-slide">
106 <div class="rc-page rc-page03">
107 <div class="rc-content-wrapper">
108 <div
109 class="rc-text-wrapper"
110 :style="{visibility: pageIndex === 2 ? \'visible\' : \'hidden\'}"
111 ref="ptwth">
112 <h2>{{langs.PAGE_THREE_SLOGAN}}</h2>
113 </div>
114 <div class="rc-cars-gallery">
115 <div
116 v-for="(car, index) in langs.CARS_PROFILE"
117 :key="index"
118 class="rc-car">
119 <div class="rc-car-card" :title="langs.CARS_TOOLTIP">
120 <div class="rc-car-media">
121 <div
122 :style="{backgroundImage: \'url(\' + common.CARS_PATH[index] + \')\'}"
123 class="rc-bg rc-bg-scale rc-car-snapshot"></div>
124 </div>
125 <div class="rc-car-profile">
126 <h4>{{car.NAME}}</h4>
127 <div>{{langs.OWNER_LABEL}}: {{car.OWNER}}</div>
128 <div>{{langs.DATE_LABEL}}: {{car.DATE}}</div>
129 </div>
130 </div>
131 </div>
132 </div>
133 </div>
134 </div>
135 </div>
136
137 <!--第四页-->
138 <div class="swiper-slide">
139 <div class="rc-page rc-page04">
140 <div
141 class="rc-text-wrapper"
142 :style="{visibility: pageIndex === 3 ? \'visible\' : \'hidden\'}"
143 ref="ptwf">
144 <h2>{{langs.PAGE_FOUR_SLOGAN}}</h2>
145 </div>
146 <div class="rc-content-wrapper">
147 <div class="rc-bg rc-drive-stage">
148 <div
149 :style="{backgroundImage: \'url(\' + common.DRIVE_STAGE_ACTOR + \')\'}"
150 class="rc-bg rc-actor-car" ref="pdcf"></div>
151 </div>
152 </div>
153 </div>
154 </div>
155 </div>
156 <div class="swiper-pagination" v-show="!isMobile"></div>
157 </div>
158 </div>
159 </template>
160
161 <script>
162 /* eslint-disable */
163 import Swiper from \'swiper\'
164 import \'swiper/dist/css/swiper.min.css\'
165 import \'animate.css/animate.min.css\'
166 import config from \'../config\'
167 import ScrollNumber from \'@/widgets/ScrollNumber.vue\'
168 export default {
169 name: \'Homepage\',
170 components: {
171 ScrollNumber
172 },
173 data () {
174 return {
175 lang: \'chinese\',
176 pageIndex: 0,
177 stepIndex: 0
178 }
179 },
180 beforeCreate () {
181 /**
182 * 旋转星空
183 * step 3: 计算可视区域对角线, 根据对角线长度撑开容器
184 */
185 let w = document.body.clientWidth
186 let h = document.body.clientHeight
187 this.layerEdge = \'calc(50% - \' + Math.ceil(Math.sqrt(w * w + h * h) / 2) + \'px)\'
188 },
189 mounted () {
190 this.$nextTick(function () {
191 let _self = this
192 /* eslint-disable no-new */
193 new Swiper(\'.rc-body\', {
194 speed: 800,
195 direction: \'vertical\',
196 paginationClickable: true,
197 mousewheel: true,
198 pagination: {
199 el: \'.swiper-pagination\'
200 },
201 on: {
202 slideChangeTransitionEnd () {
203 _self.pageIndex = this.activeIndex
204 _self.animatePage()
205 }
206 }
207 })
208 this.initPage()
209 })
210 },
211 methods: {
212 addClass (el, _class) {
213 let elClassArr = el.className.split(\' \') //用单个空格分割
214 let classArr = _class.split(\' \') //同上
215 classArr.forEach(item => {
216 // 如果elClassArr中没有这个元素(类型),那么添加进去
217 if (elClassArr.indexOf(item) === -1) {
218 elClassArr.push(String(item))
219 }
220 })
221 //添加完后本属性后面要有一个空格隔开
222 el.className = elClassArr.join(\' \')
223 return el
224 },
225 removeClass (el, _class) {
226 let elClassArr = el.className.split(\' \')
227 let classArr = _class.split(\' \')
228 classArr.forEach(item => {
229 let index = elClassArr.indexOf(item)
230 if (index > -1) {
231 elClassArr.splice(index, 1)
232 }
233 })
234 el.className = elClassArr.join(\' \')
235 return el
236 },
237 bindAnimation (el, x) {
238 let _self = this
239 // 监听动画结束事件
240 let events = [
241 \'webkitAnimationEnd\',
242 \'mozAnimationEnd\',
243 \'MSAnimationEnd\',
244 \'oanimationend\',
245 \'animationend\'
246 ]
247 _self.addClass(el, x + \' animated\')
248 events.forEach(event => {
249 let func = function () {
250 events.forEach(item => {
251 el.removeEventListener(item, func)
252 })
253 _self.removeClass(el, x + \' animated\')
254 }
255 //增加事件监听,如果时间结束,那么再利用fun函数移除监听的事件和添加进来的新类(class属性)
256 el.addEventListener(event, func)
257 })
258 },
259 initPage01 () {
260 setTimeout(() => {
261 /**
262 * 旋转星空
263 * step 4: 采用真实图片替换代理图片
264 */
265 this.$refs.plto.style.backgroundImage = \'url(\' + this.common.GALAXY_REAL_TOP + \')\'
266 this.$refs.plbo.style.backgroundImage = \'url(\' + this.common.GALAXY_REAL_BG + \')\'
267 }, 2000)
268 this.animatePage01() //动画效果(数字上升)
269 },
270 //第二页
271 initPage02 () {
272 let _self = this
273 let pbdt = this.$refs.pbdt[0]
274 let pbat = this.$refs.pbat[0]
275 let bindAnimation = this.bindAnimation
276 new Swiper(\'.rc-step-container\', {
277 speed: 600,
278 scrollbar: {
279 el: \'.swiper-scrollbar\',
280 draggable: true
281 },
282 navigation: {
283 nextEl: \'.swiper-button-next\',
284 prevEl: \'.swiper-button-prev\'
285 },
286 on: {
287 slideChangeTransitionEnd () {
288 if (this.activeIndex === 0) {
289 bindAnimation(pbdt, \'tada\')
290 } else if (this.activeIndex === 1) {
291 bindAnimation(pbat, \'tada\')
292 }
293 _self.stepIndex = this.activeIndex
294 }
295 }
296 })
297 },
298 initPage03 () {},
299 initPage04 () {},
300
301 //初始化四个界面方法
302 initPage () {
303 this.initPage01()
304 this.initPage02()
305 this.initPage03()
306 this.initPage04()
307 },
308
309 animatePage01 () {
310 this.bindAnimation(this.$refs.ptwo, \'fadeIn\')
311 this.bindAnimation(this.$refs.pbro, \'fadeIn\')
312 this.$refs.psno.$emit(\'start\')
313 },
314 animatePage02 () {
315 this.bindAnimation(this.$refs.ptwt, \'fadeInDown\')
316 },
317 animatePage03 () {
318 this.bindAnimation(this.$refs.ptwth, \'flipInY\')
319 },
320 animatePage04 () {
321 this.bindAnimation(this.$refs.ptwf, \'jackInTheBox\')
322 setTimeout(() => {
323 this.bindAnimation(this.$refs.pdcf, \'rc-arrive\')
324 }, 600)
325 },
326 // QA: 函数本是对象
327 animatePage (index) {
328 [
329 this.animatePage01,
330 this.animatePage02,
331 this.animatePage03,
332 this.animatePage04
333 ][index || this.pageIndex]()
334 },
335 //切换语言
336 toggleLang (lang) {
337 this.lang = lang
338 // this.animatePage()
339 }
340 },
341 //以下几个computed是获取config文件夹里的数据
342 computed: {
343 langs () {
344 return config.langs[this.lang]
345 },
346 media () {
347 return config.media[this.lang]
348 },
349 common () {
350 return config.common
351 },
352 // 判断移动端,无需记住,会用就好,返回值为bool值
353 isMobile () {
354 return 这个就不给了,这个直接用就好了355 }
356 }
357 }
358 </script>
359
360 <style scoped>
361 </style>
widgets/ScrollNumber.vue(数字增长):
1 <template>2 <div class="scroll-number" :style="{fontSize: size + \'px\'}">
3 <slot name="prefix"></slot>
4 <span class="number">{{value}}</span>
5 <slot name="suffix"></slot>
6 </div>
7 </template>
8
9 <script>
10 import TWEEN from \'tween.js\'
11 export default {
12 name: \'ScrollNumber\',
13 data () {
14 return {
15 value: 0,
16 animation: null
17 }
18 },
19 props: {
20 total: {
21 type: Number,
22 default: 15374
23 },
24 size: {
25 type: Number,
26 default: 24
27 }
28 },
29 mounted () {
30 this.$nextTick(function () {
31 const animate = function (time) {
32 requestAnimationFrame(animate)
33 TWEEN.update(time)
34 }
35 requestAnimationFrame(animate)
36 let _self = this
37 // 增长起始值,从0开始
38 let surface = {value: 0}
39 // 增加从0增长到total动画1600为时间
40 this.animation = new TWEEN.Tween(surface).to({value: _self.total}, 1600)
41 this.animation.easing(TWEEN.Easing.Exponential.Out).onUpdate(() => {
42 _self.value = Math.floor(surface.value)
43 })
44 // 监听父组件通讯事件
45 this.$on(\'start\', () => {
46 surface.value = 0
47 this.animation.start()
48 })
49 })
50 }
51 }
52 </script>
53
54 <style scoped>
55 .number {
56 display: inline-block;
57 min-width: 40px;
58 color: orangered;
59 text-align: center;
60 font-weight: 600;
61 }
62 </style>
注:其中TWEEN的用法我找到了一篇比较不错的文章,地址:https://www.jianshu.com/p/164538a89939
以上是 Vue.js项目实战-多语种网站(租车) 的全部内容, 来源链接: utcz.com/z/376231.html