用Vue.js开发一个电影App的前端界面

用Vue.js开发一个电影App的前端界面

我们要构建一个什么样的App?

我们大多数人使用在线流媒体服务(如Netflix)观看我们最喜欢的电影或者节目。这篇文章将重点介绍如何通过使用vue.js 2 建立一个类似风格的电影流媒体WEB交互界面(见上图)。

最终的产品可以去这里找:https://codepen.io/itslit/full/mvvjzr。

注:本文作者Hassan Djirdeh,由汇智网(***,包含很多vue.js的优秀教程)的小智翻译。

尽管Bulma将作为应用的CSS框架,但是本文将主要集中在Vue.js的使用和浏览CSS式样,如果你想跟着学,我设置了一个可以作为开始学习的地方,所有自定义组合,初始数据对象和必要的需要通过CDN引用的外部库(如Vue-router等),都可以从https://codepen.io/itslit/pen/qmzrev获得。

App的基本需求

让我们记下这些基本需求:

  1. 介绍(登录)屏幕

  2. 页脚要允许用户可以选择自己想要的电影

  3. 一个电影屏幕,显示电影的标题/描述和并且有“立即播放”的提示。

  4. 一个电影预告片屏幕,在电影播放时显示电影的预告片。

  5. 可以将电影添加到收藏夹中

我们将创建应用程序,让页脚随时出现,而首页、电影和电影预告片将共享相同的屏幕。

数据

为了简单起见,我们将从一个简单/可靠的数据对象(对象)开始,它将作为我们所有组件的主存储器。这个存储对象将拥有我们所需要的所有电影信息,并将集中在克里斯托弗·诺兰的令人敬畏的电影。下面是数据对象的一部分:

const movies = {

"dunkirk": {

"id": 'dunkirk'

"title": 'Dunkirk',

"subtitle": 'Dunkirk',

"description": 'Miraculous evacuation of Allied soldiers from Belgium, Britain, Canada, and France, who were cut off and surrounded by the German army from the beaches and harbor of Dunkirk, France, during the Battle of France in World War II.',

"largeImgSrc": `url('https://image.tmdb.org/t/p/w780/fudEG1VUWuOqleXv6NwCExK0VLy.jpg')`,

"smallImgSrc': 'https://image.tmdb.org/t/p/w185/fudEG1VUWuOqleXv6NwCExK0VLy.jpg',

"releaseDate": 'July 21 2017',

"duration": '1hr 46min',

"genre": 'Action, Drama, History',

"trailerPath": 'https://www.youtube.com/embed/F-eMt3SrfFU',

"favorite": false

},

"interstellar": {

...

},

"the-dark-knight-rises": {

...

},

"inception": {

...

},

"the-prestige": {

...

}

}

让我们开始构建App

既然我们已经创建了主要的存储对象并理解了我们的所有组件是如何布局的,我们就可以开始构建接口了。

让我们首先创建Vue实例。我们将把实例挂载到DOM元素app,并返回全局存储的movies,作为我们的HTML中访问的实例数据对象的一部分。

const rootApp = new Vue({

el: '#app',

data() {

return {

movieChoices: movies

}

}

})

我们现在可以开始处理每个独立的组件了。

页脚部分

让我们从列出数据存储中所有电影的固定页脚部分开始。

<div id="app">

<section class="hero is-primary is-medium">

<div class="hero-foot">

<div class="columns is-mobile">

<div v-for="movieChoice in movieChoices" class="column">

<li class="movie-choice">

<img :src="`${movieChoice.smallImgSrc}`" class="desktop"/>

<p class="mobile">{{ movieChoice.subtitle }}</p>

</li>

</div>

</div>

</div>

</section>

</div>

对已在上述粗体代码片段的部分:

  1. 我们用id="app"创建的DOM元素,在那里我们的Vue实例将被挂载。

  2. 我们使用的是原生的v-for指令从数据源movieChoices渲染列表。

  3. 在每一个movieChoice:

  • 我们将绑定一个图像的src到描述我们电影的smallImgSrc对象内的url(“desktop”)。

  • 我们用Mustache语法,数据绑定到movieChoice.subtitle作为手机屏幕文本显示内容。

随着所有CSS样式的渲染,我们的应用程序目前应该像这样:

用Vue.js开发一个电影App的前端界面

桌面页脚

用Vue.js开发一个电影App的前端界面

手机端页脚

电影介绍组件(和Vue-router)

我们创建了页脚,现在我们的目标是创建一个具有我们的App标题和描述的电影介绍组件。

我们已经提到了组件将共享相同的屏幕为即将上映的电影预告片和组件(即用户将能够在我们的APP中直接通过点击Intro -> Movie -> MovieComponent到达相应的链接)。

这是一个完美的用例添加vue-router库。vue-routervue.js官方路由器,是允许组件深入的集成的可配置的路由器,还可以嵌套/视图映射等等。

我们将在js文件中进行基本路由设置:

const Intro = {

template:

`<div class="hero-body" style="background: #1e1d1d">

<div class="container has-text-centered">

<div class="columns">

<div class="column is-half is-offset-one-quarter vertical-align">

<h1 class="home-intro">

VueFlix

</h1>

<p class="home-subintro">Select a movie below from the list of critically acclaimed Christopher Nolan films.</p>

</div>

</div>

</div>

</div>`

}

const routes = [

{ path: '/', component: Intro },

]

const router = new VueRouter({

routes

})

上面你可以看到我们定义的第一个路由组件Intro,我们路由这个组件{ path: '/', component: Intro }和实例化我们的路由new VueRouter({ routes })

注:通过Vue有多种方式定义组件模板。电影介绍和电影详细页的组件使用ES6的模板文本,定义模板的多个路径。Anthony Gore有一篇文章: 7 Ways To Define A Component Template in Vue.js。

我们现在需要注入我们的router到Vue实例,这使整个App的路由和渲染到我们的DOM<router-view></router-view>。

注入我们的router到Vue实例:

const rootApp = new Vue({

el: '#app',

router: router,

data() {

return {

movieChoices: movies

}

}

})

DOM中渲染我们的路由组件:

<div id="app">

<section class="hero is-primary is-medium">

<router-view></router-view>

<div class="hero-foot">

<div class="columns">

<div v-for="movieChoice in movieChoices" class="column">

<li class="movie-choice">

<img :src="`${movieChoice.smallImgSrc}`" class="desktop"/>

<p class="mobile">{{ movieChoice.subtitle }}</p>

</li>

</div>

</div>

</div>

</section>

</div>

我们已经成功地创建了我们的第一个根路径:path: '/'来显示我们的IntroComponent。随着我们添加的所有样式,我们的应用程序应该如下所示:

用Vue.js开发一个电影App的前端界面

电影组件(多路由)

我们现在App已经完成我们指定的主要路径和我们的页脚部分布局。让我们将路径扩展到显示特定电影所有信息的电影组件。

首先,让我们正确地设置导航。如前所述,我们设置页脚的目的是允许用户在电影之间导航。我们将使用Vue的vue-router的router-link组件去实现导航并提供相应的目标地址。

回到HTML并对页脚部分进行小的编辑:

<div id="app">

<section class="hero is-primary is-medium">

<router-view></router-view>

<div class="hero-foot">

<div class="columns">

<div v-for="movieChoice in movieChoices" class="column">

<router-link :to="`/${movieChoice.id}`"

tag="li"

class="movie-choice">

<img :src="`${movieChoice.smallImgSrc}`" class="desktop"/>

<p class="mobile">{{ movieChoice.subtitle }}</p>

</router-link>

</div>

</div>

</div>

</section>

</div>

我们已经建立了一个`/${movieChoice.id}`使用ES6模板文本标签的目标url作为ID的独立的电影(例如黑暗骑士崛起的路径/the-dark-knight-rises)。tag参数表明,我们希望我们的router-link作为一个li渲染,而仍然侦听点击事件。

为了补充我们的新导航路径,我们需要为我们的电影组件设置一个动态路由。回到我们设置路径的地方:

const routes = [

{ path: '/', component: Intro },

path: '/:id', component: Movie }

]

我们已经用一个动态段表示:id指向同一组件Movie每一条路由。我们现在能够通过读取$route.params.id获得不同的动态段内组件。

现在我们已经为电影组件设置了路由,让我们快速草拟组件并确保我们的路由正常工作。

电影组件的初稿:

const Movie = {

template:

`<div>

<div class="hero-body">

<div class="container has-text-centered">

<div class="columns">

<div class="column is-half is-offset-one-quarter vertical-align">

<h1 class="home-intro">

{{ selectedMovie.title }}

</h1>

</div>

</div>

</div>

</div>

</div>`,

data () {

return {

selectedMovie: movies[this.$route.params.id]

}

},

watch: {

$route () {

this.selectMovie()

}

},

methods: {

selectMovie () {

this.selectedMovie = movies[this.$route.params.id]

}

}

}

这里有几点需要注意。

data () {

return {

selectedMovie: movies[this.$route.params.id]

}

}

data函数基于$route.params.id设置组件内的selectedMovie属性,可以从全局的movies保存对象。

所以假设电影选择的是黑暗骑士崛起,这selectedMovie将是movies[the-dark-knight-rises]

watch: {

$route () {

this.selectMovie()

}

},

methods: {

selectMovie () {

this.selectedMovie = movies[this.$route.params.id]

}

}

我们用watch看路径然后有任何变化调用组件的selectMovie方法。该方法selectMovie简单更新selectedMovie参数用新电影的选择。当用户从一个电影组件切换到另一个电影组件(即开关电影)时,这是必须处理的。

测试所有的东西,我们应该能够看到路由已经工作:

用Vue.js开发一个电影App的前端界面

现在我们知道我们的路由工作得很好,我们将更新我们的电影组件中的模板来显示所有关于电影的期望信息。

const Movie = {

template:

`<div class="hero-body"

:style="{ 'background-image': selectedMovie.largeImgSrc }">

<header class="nav">

<div class="container">

<div class="nav-left">

<a class="nav-item">

<i class="fa fa-bars" aria-hidden="true"></i>

</a>

<router-link to="/" class="nav-item is-active">

Home

</router-link>

<a class="nav-item is-active">

<span class="tag is-rounded">Films</span>

</a>

<a class="nav-item is-active">

Shows

</a>

<a class="nav-item is-active">

Music

</a>

</div>

<div class="nav-right desktop">

<span class="nav-item">

<a class="title">

VueFlix

</a>

</span>

</div>

</div>

</header>

<div class="container description-container">

<div class="columns">

<div class="column is-three-quarters">

<h1 class="title">{{ selectedMovie.title }}</h1>

<h4 class="subtitle">

<p class="subtitle-tag">{{ selectedMovie.duration }}</p>

<p class="subtitle-tag">{{ selectedMovie.genre }}</p>

<p class="subtitle-tag">{{ selectedMovie.releaseDate }}</p>

</h4>

<p class="description">{{ selectedMovie.description }}</p>

<div class="links">

<router-link

:to="{path: '/' + $route.params.id + '/trailer'}"

class="button play-button">

Play <i class="fa fa-play"></i>

</router-link>

</div>

</div>

</div>

</div>

</div>`,

}

我们已经建立了一个router-link组件在首页链接在导航栏用户直接回根路径(介绍电影的部分)。

我们引入了另一个router-link,,在影片的播放按钮,创建一个目标位置的'/' + $route.params.id + '/trailer'。这基本上用/trailer扩展了电影ID的当前路径和预告片,是对我们最后的电影预告片组件的导航。

到目前为止,我们应用程序中的电影组件应该如下所示:

用Vue.js开发一个电影App的前端界面

令人惊叹的。由于我们已经建立了一个合适的router-link来引导用户从电影到电影预告片,现在我们需要创建电影预告片组件和相应的动态路由。

电影预告片:

const MovieTrailer = {

template: `

<div class="trailer-body" style="background: #1e1d1d">

<div class="has-text-centered">

<div class="columns">

<div class="column vertical-align">

<iframe

allowFullScreen

frameborder="0"

height="376"

:src="trailerUrlPath"

style="width: 100%; min-width: 536px"

/>

</div>

</div>

</div>

</div>`,

data () {

return {

trailerUrlPath: movies[this.$route.params.id].trailerPath

}

}

}

我们用一个简单的iframe显示来自YouTube上的预告片。我们绑定iframesrc到组件的属性trailerUrlPath设置在data函数。简单的trailerUrlPath访问全局的movies,得到基于$route.params.id合适的电影信息的url

伴随着动态路由:

const routes = [

{ path: '/', component: Intro },

{ path: '/:id', component: Movie },

{ path: '/:id/trailer', component: MovieTrailer }

]

我们的应用程序在这个时刻:

用Vue.js开发一个电影App的前端界面

我们差不多完成了!我们只需要再解决一个简单的添加电影收藏和VueFlix那便是完整的。

添加到收藏夹

movies中的每一个电影对象都有一个favorite的布尔值。我们将使用这个触发器来表示一个电影是否被添加到收藏夹中。

关于视觉显示,我们将有两个视觉提示:

  • 电影组件周围的黄色框阴影

  • 通过一个黄色标记列表项在页脚部分

我们通过在我们已经预留的favorite-shadowfavourite-check类的建立来帮助我们做到这些。

.favorite-shadow {

box-shadow: 0 0 50px 15px rgba(251, 255, 15, 0.25);

}

.favorite-check {

position: absolute;

right: 5px;

top: 5px;

z-index: 1;

color: #fcff4c;

@media(max-width: $medium) {

position: initial;

display: block;

}

}

现在,我们需要在Movie组件模板和页脚部分中应用条件类绑定。我们还需要为Movie组件中的“添加到收藏夹”按钮创建事件处理程序。

我们的电影组件:

const Movie = {

template:

`<div :class="[{ 'favorite-shadow': selectedMovie.favorite }, 'hero-body']"

:style="{ 'background-image': selectedMovie.largeImgSrc }">

<header class="nav">

...

</header>

<div class="container description-container">

...

...

...

<div class="links">

<router-link

:to="{path: '/' + $route.params.id + '/trailer'}"

class="button play-button">

Play <i class="fa fa-play"></i>

</router-link>

<a

class="button is-link favorites-button"

@click="addToFavorites">

<span

:class="[{ 'hide': selectedMovie.favorite }]">

Add to

</span>

<span

:class="[{ 'hide': !selectedMovie.favorite }]">

Remove from

</span>

&nbsp;favorites

<i class="fa fa-plus-square-o"></i>

</a>

</div>

</div>

</div>`,

data() {

...

},

watch: {

},

methods: {

selectMovie() {

...

},

addToFavorites() {

movies[this.$route.params.id].favorite =

!movies[this.$route.params.id].favorite

}

}

结合上述的类favorite-shadow是由selectedMovie.favorite布尔值来确定而hero-body应该永远存在。

我们还推出了'添加/删除'从收藏夹按钮后,原来的播放按钮。“添加到收藏夹”按钮从addToFavorites()方法处理简单的切换即当单击某一部电影的favorite时,文本之间切换“添加”和“删除”基于电影是否已添加或删除收藏夹(hide类是创建类设置display:none),没有就添加有就删除。

类似地,我们还需要在页脚中引入检查标记的条件类绑定:

<div id="app">

<section class="hero is-primary is-medium">

<router-view></router-view>

<div class="hero-foot">

<div class="columns is-mobile">

<div v-for="movieChoice in movieChoices" class="column">

<router-link :to="`/${movieChoice.id}`"

tag="li"

class="movie-choice">

<i :class="[{ 'fa fa-check-circle favorite-check': movieChoice.favorite }]"></i>

<img :src="`${movieChoice.smallImgSrc}`" class="desktop"/>

<p class="mobile movie-title">{{ movieChoice.subtitle }}</p>

</router-link>

</div>

</div>

</div>

</section>

</div>

现在我们应该能够把电影添加到我们的收藏夹列表中!

用Vue.js开发一个电影App的前端界面

干杯!

谢谢你花时间来看这篇文章。这是我我们一起打破瓶颈和进一步了解vue.js概念的共同的一种锻炼,所以我希望这是有益的,你学到的东西了吗?

如果你有任何问题/意见/意见,我会很高兴听到的!

本文作者Hassan Djirdeh,由汇智网(***,包含很多vue.js的优秀教程)的小智翻译。

转载于:https://www.cnblogs.com/jinhengyu/p/8158062.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/399070.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

eclipse 函数折叠展开

为什么80%的码农都做不了架构师&#xff1f;>>> 一、eclipse 代码块折叠显示 核查是否开启折叠功能全局folding(window->preference->Gerneral->Editor-Structured Text)右侧Appearance 勾选Enable folding检测对应源编辑&#xff08;java/javaScript&…

mysql 引擎 校对,MySQL 字符集和校对

字符集是指一种从二进制编码到某类字符符号的映射&#xff0c;校对是一组用于某个字符集的排序规则。每一类编码字符都有其对应的字符集和校对规则MySQL 如何使用字符集每种字符集都可能有多种校对规则&#xff0c;并且都有一个默认的校对规则。每个校对规则都是针对某个特定的…

【研究】Metasploit自动攻击模块

环境&#xff1a;kali-linux-2017.3-vm-amd64 一、安装postgresql数据库 apt-get install postgresql apt-get install rubygems libpq-dev apt-get install libreadline-dev apt-get install libssl-dev apt-get install libpq5 apt-get install ruby-dev apt-get install lib…

让nginx支持thinkphp rewrite模式

为什么80%的码农都做不了架构师&#xff1f;>>> Nginx环境在Nginx低版本中&#xff0c;是不支持PATHINFO的&#xff0c;但是可以通过在Nginx.conf中配置转发规则实现&#xff1a;在nginx配置文件中添加 location / { if (!-e $request_filename) { rewrite ^(…

WPS怎样设置多级标题(如四级标题)

WPS期初&#xff0c;乍一看最多只能设置三级标题。 怎样设置四级以上标题呢&#xff1f; 这里以设置四级标题为例&#xff1a; 点击‘视图’->大纲, 假如&#xff0c;现在2.3.3这一行是三级标题&#xff1a; 在下拉框里选择‘4级’就可以了。 现在可以回到普通页面上&#x…

matlab实现主成分分析(遥感图像处理)

数据说明&#xff1a;采用的数据源是从别人那里拷的2012年全年的Sea Surface Temperature&#xff08;海标温度&#xff0c;SST&#xff09;数据&#xff0c;一直想找一份比较好的主成分分析数据&#xff0c;也没找到。 Matlab自身有主成分分析的函数princomp&#xff0c;其中返…

SQL Server中关于跟踪(Trace)那点事

前言 一提到跟踪俩字&#xff0c;很多人想到警匪片中的场景&#xff0c;同样在我们的SQL Server数据库中“跟踪”也是无处不在的&#xff0c;如果我们利用好了跟踪技巧&#xff0c;就可以针对某些特定的场景做定向分析&#xff0c;找出充足的证据来破案。 简单的举几个应用场景…

php怎么获取用户所在地址,php获取客户端ip及获取ip所在地址

// 获取ipfunction ip(){if (isset($_SERVER["HTTP_X_FORWARDED_FOR"]))$ip $_SERVER["HTTP_X_FORWARDED_FOR"];else if (isset($_SERVER["HTTP_CLIENT_IP"]))$ip $_SERVER["HTTP_CLIENT_IP"];else$ip $_SERVER["REMOTE_ADDR&…

php若$a没定义默认是,PHP之错误处理详解

PHP之错误处理详解错误报告PHP程序的错误发生一般归属于下列三个领域&#xff1a;1、语法错误语法错误最常见&#xff0c;并且也容易修复。如&#xff1a;代码中遗漏一个分号。这类错误会阻止脚本的执行2、运行时错误这种错误一般不会阻止PHP脚本的执行&#xff0c;但会阻止当前…

热血沙城-3.2移植-古月-cocos2dx源码

最近发现我去年学习2dx的时候移植过的一个游戏现在被放在网上出售 真是有点想笑 本人比较喜欢武侠风格的游戏&#xff0c;当时9秒开源了热血沙城 本着学习的态度 从2.1.2移植到3.2 用了一周的时间 中间各种报错 大概修改了1000多处错误 同时增加了支持摇杆 后来放到9秒上开源&…

【openjudge 1.11 07】和为给定数

我看到这个的第一反应就是爆搜&#xff0c;然后写了一个没加$No$的4分程序 #include <bits/stdc.h> #include <algorithm> #define it int #define fr for #define il inline using namespace std; it book[100020],t[100020]; it spe[50010]; it n,m,bz0; it main…

matlab用泰勒展开解微分方程,mathematica的解微分方程的能力让人大失所望啊

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼Clear["Global*"]c 299792458*10^2(*光速&#xff0c;单位cm/s*)G 6.67259*10^-8(*gravitational constant&#xff0c;引力常数&#xff0c;单位cm^3/g*s^2*)Msun 1.9891*10^33(*Subscript[M, \[CircleDot]]&#xf…

Python爬虫入门项目

Python是什么 Python是著名的“龟叔”Guido van Rossum在1989年圣诞节期间&#xff0c;为了打发无聊的圣诞节而编写的一个编程语言。 创始人Guido van Rossum是BBC出品英剧Monty Python’s Flying Circus&#xff08;中文&#xff1a;蒙提派森的飞行马戏团&#xff09;的狂热粉…

spring boot 启动类

做项目用到spring boot 感觉spring boot用起来比较流畅。想总结一下&#xff0c;别的不多说&#xff0c;从入口开始。 spring boot启动类Application.class 不能直接放在main/java文件夹下 一、spring boot的入口启动类概览。 import org.springframework.context.annotation.B…

FlashFXP使用教程

点FlashFXP菜单栏“站点-站点管理”打开站点管理器。然后点新建站点&#xff0c;输入站点名称&#xff08;随意&#xff09;&#xff0c;确定。 编辑站点管理器里新建的站点的相关信息&#xff0c;包括站点名称、地址、用户名称、密码等。编辑完成&#xff0c;点应用保存站点信…

你的工作单位也需善待

善待这个词&#xff0c;常常和家人、朋友联系在一起&#xff0c;其实你不仅要善待家人和朋友&#xff0c;还要善待你所在的工作单位。单位给了你创造财富生存的机会&#xff0c;给了你发挥聪明才智的平台&#xff0c;给了你体现人生价值的天空&#xff0c;所以要善待它。在单位…

识别图片baidu ai php,PHP+百度AI OCR文字识别实现了图片的文字识别功能

第一步可定要获取百度的三个东西 要到百度AI网站(http://ai.baidu.com/)去注册 然后获得-const APP_ID 请填写你的appid;-const API_KEY 请填写你的API_KEY;-const SECRET_KEY 请填写你的SECRET_KEY;第二步下载SDK或者使用官方的 http://ai.baidu.com/sdk 下载第三步 然后就…

深入理解javascript原型和闭包(4)——隐式原型

注意&#xff1a;本文不是javascript基础教程&#xff0c;如果你没有接触过原型的基本知识&#xff0c;应该先去了解一下&#xff0c;推荐看《javascript高级程序设计&#xff08;第三版&#xff09;》第6章&#xff1a;面向对象的程序设计。 上节已经提到&#xff0c;每个函数…

ecshop 手机版的php代码在哪里,PHP 在ecshop上集成 手机网页支付_php

参考alipay网页支付接口的代码其实原理跟ecshop上集成的alipay支付差不多 就是因为利用curl请求的时候相应时间过长 所以不能直接去先post数据再生成button/*** 生成支付代码* param array $order 订单信息* param array $payment 支付方式信息*/function get…

技术回归本位:海尔引领空调产业重构格局

当前&#xff0c;互联网新思维方式日趋侵染&#xff0c;越来越多的细分领域在“互联网”理念下纷纷尝试跨界探索新的创新&#xff0c;一些商家除了推出全新战略型产品和服务之外&#xff0c;还在主打营销概念争夺舆论风口方面投入了巨大的精力与资源。在这种以理念为中心的时代…