Vue.js项目实战-多语种网站(租车)

vue

首先来看一下网站效果,想写这个项目的读者可以自行下载哦,地址: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>&nbsp;/

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}}:&nbsp;{{car.OWNER}}</div>

128 <div>{{langs.DATE_LABEL}}:&nbsp;{{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

回到顶部