当前位置:   article > 正文

React项目案例-影视资源网站_react-responsive-carousel

react-responsive-carousel

案例项目基本需求分析

  • 前端页面布局使用Chakra-UI

  • 后端服务使用Next.js

  • 样式定义采用CSS-in-JS的方案,使用emotion库(需要在Next.js扩展babel配置)

  • Next.js 与Chakra-UI结合使用实现项目页面的功能

  • 首页(列表页)的轮播图,以及影视资源列表展示

项目代码初始化

运行安装依赖包命令:

npm init next-app aimovie
cd aimovie
#npm i @chakra-ui/react
#npm i @chakra-ui/react@^1 @emotion/react@^11 @emotion/styled@^11 framer-motion@^6
npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion
npm i react-icons
npm i @babel/core @emotion/babel-preset-css-prop -D
  1. {
  2. "name": "aimovie",
  3. "version": "0.1.0",
  4. "private": true,
  5. "scripts": {
  6. "dev": "next dev",
  7. "build": "next build",
  8. "start": "next start",
  9. "lint": "next lint"
  10. },
  11. "dependencies": {
  12. "@babel/core": "^7.21.0",
  13. "@chakra-ui/react": "^2.5.1",
  14. "@emotion/react": "^11.10.6",
  15. "@emotion/styled": "^11.10.6",
  16. "framer-motion": "^10.2.5",
  17. "next": "13.2.4",
  18. "react": "18.2.0",
  19. "react-dom": "18.2.0",
  20. "react-icons": "^4.8.0"
  21. }
  22. }

创建pages目录下的 _app.js 文件:

  1. // import '@/styles/globals.css'
  2. // pages/_app.js
  3. import { ChakraProvider, CSSReset } from '@chakra-ui/react'
  4. import theme from '../chakra'
  5. function App ({ Component, pageProps }) {
  6. return (
  7. <ChakraProvider theme={theme}>
  8. <CSSReset />
  9. <Component {...pageProps} />
  10. </ChakraProvider>
  11. )
  12. }
  13. export default App

创建 .babelrc 文件作为babel的配置文件:(在新版的next.js中不需要配置,默认开启了cssProp,否则会产生next/font冲突)

  1. {
  2. "presets": [
  3. "next/babel",
  4. "@emotion/babel-preset-css-prop"
  5. ]
  6. }

页面组件规划与布局实现

实现页面头部组件

头部组件包含三部分:左侧的登录注册按钮组件 中间的网站logo 右边的搜索按钮。

布局规划:左浮动 有浮动 中间logo始终居中。

创建components文件夹,用于存放非页面层级的组件。

头部组件基本布局:

  1. import React from 'react'
  2. import { Box, Button, Container, Image } from '@chakra-ui/react'
  3. import { FaSearch, FaSignInAlt, FaUserAlt } from 'react-icons/fa'
  4. import styled from '@emotion/styled'
  5. import { css } from '@emotion/react'
  6. const SignInAndJoin = styled.div`
  7. height: 52px;
  8. line-height: 52px;
  9. color: #fff;
  10. border-left: 1px solid #393939;
  11. border-right: 1px solid #393939;
  12. padding: 0 6px;
  13. float: left;
  14. `
  15. const logo = css`
  16. position: absolute;
  17. left: 50%;
  18. top: 50%;
  19. transform: translate(-50%, -50%);
  20. width: 140px;
  21. height: auto;
  22. `
  23. const Search = styled.a`
  24. float: right;
  25. height: 52px;
  26. border-left: 1px solid #393939;
  27. border-right: 1px solid #393939;
  28. color: #fff;
  29. padding: 0 10px;
  30. display: flex;
  31. align-items: center;
  32. `
  33. export default function Header () {
  34. return (
  35. <Box h='52px' bgColor='#202020' borderBottom='1px solid #393939'>
  36. <Container pos='relative' h='52px' maxW='1200px'>
  37. <SignInAndJoin>
  38. <Button
  39. mr='5px'
  40. leftIcon={<FaSignInAlt />}
  41. colorScheme='teal'
  42. variant='solid'
  43. >
  44. 登录
  45. </Button>
  46. <Button
  47. leftIcon={<FaUserAlt />}
  48. colorScheme='orange'
  49. variant='outline'
  50. >
  51. 注册
  52. </Button>
  53. </SignInAndJoin>
  54. <Image css={logo} src='/images/logo.png' />
  55. <Search>
  56. <FaSearch size='16px' title='搜索' />
  57. </Search>
  58. </Container>
  59. </Box>
  60. )
  61. }

实现导航组件布局

  1. import React from 'react'
  2. import { Box, HStack, Link } from '@chakra-ui/react'
  3. import NextLink from 'next/link'
  4. import styles from '@/styles/Navigation.module.css'
  5. import { useRouter } from 'next/router'
  6. export default function Navigation () {
  7. const router = useRouter()
  8. const isActiveLink = href => router.asPath === href
  9. return (
  10. <Box height='52px' bgColor='#202020' color='#fff'>
  11. <HStack h='100%' spacing={3} justifyContent='center' alignItems='center'>
  12. <Link
  13. className={`${styles.navlink} ${
  14. isActiveLink('/') ? styles.active : ''
  15. }`}
  16. href='/'
  17. as={NextLink}
  18. >
  19. 影片
  20. </Link>
  21. <Link
  22. className={`${styles.navlink} ${
  23. isActiveLink('/1') ? styles.active : ''
  24. }`}
  25. href='/1'
  26. as={NextLink}
  27. >
  28. 漫画
  29. </Link>
  30. <Link
  31. className={`${styles.navlink} ${
  32. isActiveLink('/2') ? styles.active : ''
  33. }`}
  34. href='/2'
  35. as={NextLink}
  36. >
  37. 电影
  38. </Link>
  39. <Link
  40. className={`${styles.navlink} ${
  41. isActiveLink('/3') ? styles.active : ''
  42. }`}
  43. href='/3'
  44. as={NextLink}
  45. >
  46. 电视
  47. </Link>
  48. <Link
  49. className={`${styles.navlink} ${
  50. isActiveLink('/4') ? styles.active : ''
  51. }`}
  52. href='/4'
  53. as={NextLink}
  54. >
  55. 新闻资讯
  56. </Link>
  57. </HStack>
  58. </Box>
  59. )
  60. }

实现轮播图组件布局

这里使用到一个第三方组件react-responsive-carousel

npm i react-responsive-carousel
  1. import React from 'react'
  2. import { Carousel } from 'react-responsive-carousel'
  3. import 'react-responsive-carousel/lib/styles/carousel.min.css'
  4. import { css } from '@emotion/react'
  5. import { Box, Stack, Heading, Text, Button } from '@chakra-ui/react'
  6. import styled from '@emotion/styled'
  7. const CarouselItem = styled.div`
  8. position: relative;
  9. & > div {
  10. position: absolute;
  11. left: 50%;
  12. top: 0;
  13. transform: translateX(-50%);
  14. color: #fff;
  15. width: 80%;
  16. height: 100%;
  17. max-width: 1200px;
  18. text-align: left;
  19. & > h2 {
  20. width: 450px;
  21. }
  22. & > p {
  23. margin: 15px 0;
  24. width: 450px;
  25. }
  26. }
  27. & > img {
  28. filter: brightness(50%);
  29. }
  30. `
  31. const swiperContainer = css`
  32. & > .carousel-root {
  33. position: relative;
  34. & > .carousel:last-child {
  35. position: absolute;
  36. left: 0;
  37. bottom: 0;
  38. & > .thumbs-wrapper > .thumbs {
  39. display: flex;
  40. justify-content: center;
  41. }
  42. }
  43. }
  44. `
  45. export default function Swiper () {
  46. return (
  47. <Box css={swiperContainer}>
  48. <Carousel
  49. // autoPlay
  50. infiniteLoop
  51. emulateTouch
  52. showArrows={false}
  53. showIndicators={false}
  54. showStatus={false}
  55. >
  56. <CarouselItem>
  57. <img src='/images/1.jpg' />
  58. <Stack justifyContent='center'>
  59. <Heading as='h1' size={'lg'}>
  60. King In Black
  61. </Heading>
  62. <Text>
  63. The next shock chapter in Donny Cates and Ryan Stegman hello look
  64. at me! shock chapter in Donny Cates and Ryan Stegman hello look at
  65. me!
  66. </Text>
  67. <Button colorScheme='red' w='150px'>
  68. Go To This
  69. </Button>
  70. </Stack>
  71. </CarouselItem>
  72. <CarouselItem>
  73. <img src='/images/2.jpg' />
  74. <Stack justifyContent='center'>
  75. <Heading as='h1' size={'lg'}>
  76. King In Black
  77. </Heading>
  78. <Text>
  79. The next shock chapter in Donny Cates and Ryan Stegman hello look
  80. at me! shock chapter in Donny Cates and Ryan Stegman hello look at
  81. me!
  82. </Text>
  83. <Button colorScheme='red' w='150px'>
  84. Go To This
  85. </Button>
  86. </Stack>
  87. </CarouselItem>
  88. <CarouselItem>
  89. <img src='/images/3.jpg' />
  90. <Stack justifyContent='center'>
  91. <Heading as='h1' size={'lg'}>
  92. King In Black
  93. </Heading>
  94. <Text>
  95. The next shock chapter in Donny Cates and Ryan Stegman hello look
  96. at me! shock chapter in Donny Cates and Ryan Stegman hello look at
  97. me!
  98. </Text>
  99. <Button colorScheme='red' w='150px'>
  100. Go To This
  101. </Button>
  102. </Stack>
  103. </CarouselItem>
  104. </Carousel>
  105. </Box>
  106. )
  107. }

实现电影列表布局

  1. import React from 'react'
  2. import { Box, Heading, HStack, Text } from '@chakra-ui/react'
  3. import { FaFilm } from 'react-icons/fa'
  4. import { MdMovie } from 'react-icons/md'
  5. export default function Movie () {
  6. return (
  7. <Box maxW='1200px' mx='auto' mt='20px'>
  8. <HStack fontSize='24px' my='10px'>
  9. <MdMovie size='24px' />
  10. <Heading as='h3'>电影</Heading>
  11. </HStack>
  12. <HStack mt='20px' spacing={3}>
  13. <Box w={'290px'}>
  14. <img src='/images/item_1.jpg' />
  15. <Text mt='10px' as='section'>
  16. Expected corresponding JSX closing tag for Black Hero
  17. </Text>
  18. </Box>
  19. <Box w={'290px'}>
  20. <img src='/images/item_1.jpg' />
  21. <Text mt='10px' as='section'>
  22. Expected corresponding JSX closing tag for Black Hero
  23. </Text>
  24. </Box>
  25. <Box w={'290px'}>
  26. <img src='/images/item_1.jpg' />
  27. <Text mt='10px' as='section'>
  28. Expected corresponding JSX closing tag for Black Hero
  29. </Text>
  30. </Box>
  31. <Box w={'290px'}>
  32. <img src='/images/item_1.jpg' />
  33. <Text mt='10px' as='section'>
  34. Expected corresponding JSX closing tag for Black Hero
  35. </Text>
  36. </Box>
  37. <Box w={'290px'}>
  38. <img src='/images/item_1.jpg' />
  39. <Text mt='10px' as='section'>
  40. Expected corresponding JSX closing tag for Black Hero
  41. </Text>
  42. </Box>
  43. <Box w={'290px'}>
  44. <img src='/images/item_1.jpg' />
  45. <Text mt='10px' as='section'>
  46. Expected corresponding JSX closing tag for Black Hero
  47. </Text>
  48. </Box>
  49. </HStack>
  50. </Box>
  51. )
  52. }

实现电影详情页面布局

  1. import Layout from '@/components/Layout'
  2. import React from 'react'
  3. import { Box, HStack, Text, Heading, Divider } from '@chakra-ui/react'
  4. import { css } from '@emotion/react'
  5. const DetailContainer = css`
  6. padding: 10px;
  7. & > p {
  8. font-size: 14px;
  9. margin-bottom: 10px;
  10. }
  11. & > img {
  12. display: block;
  13. margin-bottom: 10px;
  14. }
  15. `
  16. export default function Detail () {
  17. return (
  18. <Layout>
  19. <Box maxW='1200px' mx='auto' width='80%' mt='70px'>
  20. <Heading as='h2' size='xl'>
  21. Marvel Mission recap: Captain Marvel's Star of Hala
  22. </Heading>
  23. <Heading
  24. as='h4'
  25. size='lg'
  26. mt='10px'
  27. color='gray.500'
  28. fontWeight='light'
  29. >
  30. The result are out this world!
  31. </Heading>
  32. <Divider mt='10px' />
  33. <HStack
  34. overflow='hidden'
  35. justifyContent='space-between'
  36. spacing={3}
  37. my='10px'
  38. >
  39. <Text>作者: MarkTony</Text>
  40. <Text>发布时间: 2040-05-10</Text>
  41. </HStack>
  42. <Divider mt='10px' />
  43. <Box css={DetailContainer}>
  44. <p>
  45. event - compiled client and server successfully in 377 ms (1213
  46. modules) wait - compiling... event - compiled client and server
  47. successfully in 520 ms (1213 modules) wait - compiling... event -
  48. compiled client and server successfully in 646 ms (1213 modules)
  49. wait - compiling...
  50. </p>
  51. <p>
  52. event - compiled client and server successfully in 377 ms (1213
  53. modules) wait - compiling... event - compiled client and server
  54. successfully in 520 ms (1213 modules) wait - compiling... event -
  55. compiled client and server successfully in 646 ms (1213 modules)
  56. wait - compiling...
  57. </p>
  58. <p>
  59. event - compiled client and server successfully in 377 ms (1213
  60. modules) wait - compiling... event - compiled client and server
  61. successfully in 520 ms (1213 modules) wait - compiling... event -
  62. compiled client and server successfully in 646 ms (1213 modules)
  63. wait - compiling...
  64. </p>
  65. <p>
  66. event - compiled client and server successfully in 377 ms (1213
  67. modules) wait - compiling... event - compiled client and server
  68. successfully in 520 ms (1213 modules) wait - compiling... event -
  69. compiled client and server successfully in 646 ms (1213 modules)
  70. wait - compiling...
  71. </p>
  72. </Box>
  73. </Box>
  74. </Layout>
  75. )
  76. }

实现首页组件的静态生成

轮播图数据获取与展示

这里我们需要使用到axios库来发送请求以获取我们所需的数据:

npm i axios

在根目录下创建一个axiosConfig.js文件:

  1. export const baseURL = 'http://localhost:3000'
  2. export default {
  3. // thrid-party API base URL
  4. baseURL
  5. }

在pages/api目录下创建swiper.js的文件,模拟获取swiper的API供组件调用:

  1. import { baseURL as url } from '@/axiosConfig'
  2. export default function swiper (req, res) {
  3. res.status(200).json([
  4. {
  5. id: 1,
  6. title: 'Event-Sized Episode!',
  7. description:
  8. "Paul Scheer and Steve Wacker are joined by Anthony Carboni of 'The Star Wars Show' for an event sized episode!",
  9. url: `${url}/apiresources/images/api_swiper_1.jpg`,
  10. vid: 1
  11. },
  12. {
  13. id: 2,
  14. title: 'Time Travel Tips',
  15. description:
  16. 'Traveling back in time is never easy? Let us help by consulting the pros!',
  17. url: `${url}/apiresources/images/api_swiper_2.jpg`,
  18. vid: 2
  19. },
  20. {
  21. id: 3,
  22. title: 'KING IN BLACK',
  23. description:
  24. "The next shocking chapter in Donny Cates and Ryan Stegman's Venom Saga is revealed!",
  25. url: `${url}/apiresources/images/api_swiper_3.jpg`,
  26. vid: 3
  27. },
  28. {
  29. id: 4,
  30. title: "LET'S PLAY FORTNITE",
  31. description:
  32. 'Watch as we stream the brand new Captain America outfit in Fortnite!',
  33. url: `${url}/apiresources/images/api_swiper_4.jpg`,
  34. vid: 4
  35. },
  36. {
  37. id: 5,
  38. title: 'HAPPY ULTRAMAN DAY!',
  39. description:
  40. "Celebrate by getting a sneak peek at 'Rise of Ultraman #1'!",
  41. url: `${url}/apiresources/images/api_swiper_5.jpg`,
  42. vid: 5
  43. }
  44. ])
  45. }

components/Swiper.js组件文件中,创建并导出loadSwiper函数:

  1. // components/Swiper.js
  2. export function loadSwiper () {
  3. // 这离获取数据不建议从本地通过API接口获取,而应该通过封装后端的方法函数直接操作数据库获取
  4. // 如果是第三方API可以通过API接口获取数据
  5. return axios.get('/api/swiper', { baseURL: 'http://localhost:3000/' })
  6. }

然后在首页的Home组件(pages/index.js)中,创建并导出getStaticProps函数,并且在Home组件中解构组件的props获取swiper数据对象,把swiper作为data属性传递给Swiper组件:

  1. import Image from 'next/image'
  2. // import { Inter } from 'next/font/google'
  3. import styles from '@/styles/Home.module.css'
  4. import Swiper, { loadSwiper } from '@/components/Swiper'
  5. import Movie from '@/components/Movie'
  6. import Layout from '@/components/Layout'
  7. // const inter = Inter({ subsets: ['latin'] })
  8. export default function Home ({ swiper }) {
  9. return (
  10. <>
  11. <Layout>
  12. <Swiper data={swiper} />
  13. <Movie />
  14. </Layout>
  15. </>
  16. )
  17. }
  18. export async function getStaticProps () {
  19. let { data: swiper } = await loadSwiper()
  20. return {
  21. props: {
  22. swiper
  23. }
  24. }
  25. }

使用传递给components/Swiper.js组件的数据修改组件内容展示:

  1. import React from 'react'
  2. import { Carousel } from 'react-responsive-carousel'
  3. import 'react-responsive-carousel/lib/styles/carousel.min.css'
  4. import { css } from '@emotion/react'
  5. import { Box, Stack, Heading, Text, Button } from '@chakra-ui/react'
  6. import styled from '@emotion/styled'
  7. import axios from 'axios'
  8. import { useRouter } from 'next/router'
  9. const CarouselItem = styled.div`
  10. position: relative;
  11. & > div {
  12. position: absolute;
  13. left: 50%;
  14. top: 0;
  15. transform: translateX(-50%);
  16. color: #fff;
  17. width: 80%;
  18. height: 100%;
  19. max-width: 1200px;
  20. text-align: left;
  21. & > h2 {
  22. width: 450px;
  23. }
  24. & > p {
  25. margin: 15px 0 15px;
  26. width: 450px;
  27. font-size: 14px;
  28. }
  29. }
  30. & > img {
  31. filter: brightness(50%);
  32. }
  33. `
  34. const swiperContainer = css`
  35. & > .carousel-root {
  36. position: relative;
  37. & > .carousel:last-child {
  38. position: absolute;
  39. left: 0;
  40. bottom: 0;
  41. & > .thumbs-wrapper > .thumbs {
  42. display: flex;
  43. justify-content: center;
  44. }
  45. }
  46. }
  47. `
  48. export default function Swiper ({ data }) {
  49. const router = useRouter()
  50. return (
  51. <Box css={swiperContainer}>
  52. <Carousel
  53. // autoPlay
  54. infiniteLoop
  55. emulateTouch
  56. showArrows={false}
  57. showIndicators={false}
  58. showStatus={false}
  59. >
  60. {data.map(swiper => (
  61. <CarouselItem key={swiper.id}>
  62. <img src={swiper.url} />
  63. <Stack justifyContent='center'>
  64. <Heading as='h2' fontSize='4xl'>
  65. {swiper.title}
  66. </Heading>
  67. <Text>{swiper.description}</Text>
  68. <Button
  69. colorScheme='red'
  70. w='120px'
  71. size='lg'
  72. onClick={() =>
  73. router.push({
  74. pathname: '/detail/[id]',
  75. query: { id: swiper.vid }
  76. })
  77. }
  78. >
  79. CHECK DETAIL
  80. </Button>
  81. </Stack>
  82. </CarouselItem>
  83. ))}
  84. </Carousel>
  85. </Box>
  86. )
  87. }
  88. export function loadSwiper () {
  89. // 这离获取数据不建议从本地通过API接口获取,而应该通过封装后端的方法函数直接操作数据库获取
  90. // 如果是第三方API可以通过API接口获取数据
  91. return axios.get('/api/swiper', { baseURL: 'http://localhost:3000/' })
  92. }

电影列表数据的获取与展示

在pages/api目录下创建movie.js的文件,模拟获取movie的API供组件调用:

  1. import { baseURL as url } from '@/axiosConfig'
  2. export default function movie (req, res) {
  3. res.status(200).json([
  4. {
  5. id: 1,
  6. vid: 6,
  7. url: `${url}/apiresources/images/api_movie_1.jpg`,
  8. title: 'Marvel Mission Recap: Captain Marvel’s Star of Hala'
  9. },
  10. {
  11. id: 2,
  12. vid: 7,
  13. url: `${url}/apiresources/images/api_movie_2.jpg`,
  14. title: 'Make Your Video Calls Worthy With These Backgrounds'
  15. },
  16. {
  17. id: 3,
  18. vid: 8,
  19. url: `${url}/apiresources/images/api_movie_3.jpg`,
  20. title: 'Make Your Video Calls Worthy With These Backgrounds'
  21. },
  22. {
  23. id: 4,
  24. vid: 9,
  25. url: `${url}/apiresources/images/api_movie_4.jpg`,
  26. title:
  27. 'Marvel At Home: Here’s How to Stay Connected With Your Favorite Super Heroes'
  28. }
  29. ])
  30. }

components/Movie.js组件文件中,创建并导出loadMovie函数:

  1. export function loadMovie () {
  2. return axios.get('/api/movie', { baseURL })
  3. }

然后在首页的Home组件(pages/index.js)中,创建并导出getStaticProps函数,并且在Home组件中解构组件的props获取movie数据对象,把movie作为data属性传递给Movie组件:

  1. import Image from 'next/image'
  2. // import { Inter } from 'next/font/google'
  3. import styles from '@/styles/Home.module.css'
  4. import Swiper, { loadSwiper } from '@/components/Swiper'
  5. import Movie, { loadMovie } from '@/components/Movie'
  6. import Layout from '@/components/Layout'
  7. // const inter = Inter({ subsets: ['latin'] })
  8. export default function Home ({ swiper, movie }) {
  9. return (
  10. <>
  11. <Layout>
  12. <Swiper data={swiper} />
  13. <Movie data={movie} />
  14. </Layout>
  15. </>
  16. )
  17. }
  18. export async function getStaticProps () {
  19. const { data: swiper } = await loadSwiper()
  20. const { data: movie } = await loadMovie()
  21. return {
  22. props: {
  23. swiper,
  24. movie
  25. }
  26. }
  27. }

使用传递给components/Movie.js组件的数据修改组件内容展示:

  1. import React from 'react'
  2. import { Box, Heading, HStack, Text, Image } from '@chakra-ui/react'
  3. import { FaFilm } from 'react-icons/fa'
  4. import { MdMovie } from 'react-icons/md'
  5. import { baseURL } from '@/axiosConfig'
  6. import axios from 'axios'
  7. import { useRouter } from 'next/router'
  8. export default function Movie ({ data }) {
  9. const router = useRouter()
  10. return (
  11. <Box maxW='1200px' mx='auto' px='10px' mt='20px'>
  12. <HStack>
  13. <MdMovie size='18px' />
  14. <Heading as='h3' fontSize='18px'>
  15. 电影
  16. </Heading>
  17. </HStack>
  18. <HStack
  19. mt='20px'
  20. spacing='0'
  21. flexFlow='wrap'
  22. justifyContent='space-between'
  23. >
  24. {data.map(movie => (
  25. <Box
  26. onClick={() => router.push(`/detail/${movie.vid}`)}
  27. key={movie.id}
  28. w='290px'
  29. cursor='pointer'
  30. >
  31. <Image w='290px' src={movie.url} />
  32. <Text h='52px' overflow='hidden' mt='10px' as='section'>
  33. {movie.title}
  34. </Text>
  35. </Box>
  36. ))}
  37. </HStack>
  38. </Box>
  39. )
  40. }
  41. export function loadMovie () {
  42. return axios.get('/api/movie', { baseURL })
  43. }

实现详情页基于动态路由的数据获取与展示

详情页属于基于动态路由的静态生成,首先我们要做的就是在首页点击链接或按钮跳转到对应的详情页。

这需要使用到Link或者next/router。

上面的页面已经实现了此功能,这里就不再重复。

首先,创建pages/api/videos.js 来模拟获取所有video id列表的API:

  1. import { baseURL as url } from '@/axiosConfig'
  2. export const videos = [
  3. {
  4. id: '1',
  5. title:
  6. "It's an Event-Sized Episode of 'Marvel Presents: The World's Greatest Book Club with Paul Scheer' in Celebration of 'Empyre'",
  7. sub:
  8. "Paul Scheer and Steve Wacker are joined by Anthony Carboni of 'The Star Wars Show'!",
  9. author: 'JAMIE FREVELE',
  10. publish: '2050-05-26',
  11. content:
  12. "<p>Time for a new episode of Marvel Presents: The World's Greatest Book Club with Paul Scheer -- and this one, Marvelites, is super-sized! Why? Because there's a new Marvel comic event in our midst, and EMPYRE deserves no less than a big celebration with hosts Paul Scheer and Steve Wacker! Paul and Steve are joined by guest Anthony Carboni (The Star Wars Show) for a calamitous conversation about other notable Marvel events.</p><video controls src='" +
  13. url +
  14. "/apiresources/videos/1.mp4'></video><p>But first -- EMPYRE! Steve provided an inside look at the creation of the intergalactic conflict and what Marvel fans can expect:</p><p>“What [writers Al Ewing and Dan Slott] definitely wanted to get away from was making it a [Fantastic Four] versus the Avengers, yet another story where friends fight each other and try to kill each other. Much like this show.”</p><p>He went on to predict the lasting effects of EMPYRE on the Marvel Universe:</p><p>“There are some big changes coming, and I think when we’re in our sweet spot is when we at Marvel are a little nervous about how the fans are going to react. It’s our job to put them through the ringer, to put them through hell. I think EMPYRE is not the story at the beginning that you think it is.”</p>"
  15. },
  16. {
  17. id: '2',
  18. title: "Time Travel Tips from 'Marvel's Agents of S.H.I.E.L.D.'",
  19. sub:
  20. 'Traveling back in time is never easy? Let us help by consulting the pros!',
  21. author: 'CHRISTINE DINH',
  22. publish: '2050-03-13',
  23. content:
  24. "<img src='" +
  25. url +
  26. "/apiresources/images/detail_2.jpg'/><p>Look, we all know hopping through the decades ain't easy. In fact, who can keep up with all the different rules of time travel.</p><video controls src='" +
  27. url +
  28. "/apiresources/videos/2.mp4'></video><p>Luckily, we know a bunch of experts. During the production of Marvel's Agents of S.H.I.E.L.D. Season 7, Marvel.com had the opportunity to consult the cast and showrunners how to remain composure while navigating time travel. Watch what they have to say, learn the Do's and Don't's, and word of advice, it's probably best to avoid the shenanigans of Deke Shaw. We haven't forgotten the events of Season 6, Deke
    声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/446473
    推荐阅读
    相关标签