1. 程式人生 > >用Vue.js來開發一個電影App的前端部分

用Vue.js來開發一個電影App的前端部分

column 多種方式 -a 目標 部分 cli 多路由 cdn tor

技術分享圖片

我們要構建一個什麽樣的App?

我們大多數人使用在線流媒體服務(如Netflix)觀看我們最喜歡的電影或者節目。這篇文章將重點介紹如何通過使用vue.js 2建立一個類似風格的電影流媒體WEB交互界面(見上圖)。

最終的產品可以去這裏找:https://codepen.io/itslit/full/mvvjzr。

盡管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-router)

我們創建了頁腳,現在我們的目標是創建一個具有我們的App標題和描述的電影介紹組件。

我們已經提到了組件將共享相同的屏幕為即將上映的電影預告片和組件(即用戶將能夠在我們的APP中直接通過點擊Intro -> Movie -> MovieComponent到達相應的鏈接)。

這是一個完美的用例添加vue-router庫。vue-router是vue.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。隨著我們添加的所有樣式,我們的應用程序應該如下所示:

技術分享圖片

電影組件(多路由)

我們現在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參數用新電影的選擇。當用戶從一個電影組件切換到另一個電影組件(即開關電影)時,這是必須處理的。

測試所有的東西,我們應該能夠看到路由已經工作:

技術分享圖片

現在我們知道我們的路由工作得很好,我們將更新我們的電影組件中的模板來顯示所有關於電影的期望信息。

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的當前路徑和預告片,是對我們最後的電影預告片組件的導航。

到目前為止,我們應用程序中的電影組件應該如下所示:

技術分享圖片

令人驚嘆的。由於我們已經建立了一個合適的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上的預告片。我們綁定iframe的src到組件的屬性trailerUrlPath設置在data函數。簡單的trailerUrlPath訪問全局的movies,得到基於$route.params.id合適的電影信息的url。

伴隨著動態路由:

const routes = [

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

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

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

]

我們的應用程序在這個時刻:

技術分享圖片

我們差不多完成了!我們只需要再解決一個簡單的添加電影收藏和VueFlix那便是完整的。

添加到收藏夾

movies中的每一個電影對象都有一個favorite的布爾值。我們將使用這個觸發器來表示一個電影是否被添加到收藏夾中。

關於視覺顯示,我們將有兩個視覺提示:

  • 電影組件周圍的黃色框陰影

  • 通過一個黃色標記列表項在頁腳部分

我們通過在我們已經預留的favorite-shadow和favourite-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概念的共同的一種鍛煉,所以我希望這是有益的,你學到的東西了嗎?

如果你有任何問題/意見,我會很高興聽到的!

本文原作者Hassan Djirdeh,由本博主翻譯,本博主的很多vue.js教程也可以到這裏。

用Vue.js來開發一個電影App的前端部分