├── .gitignore ├── README.md ├── babel.config.js ├── demo └── images │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ ├── d1.png │ ├── d2.png │ └── d3.png ├── package-lock.json ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── assets │ └── logo.png ├── components │ ├── HelloWorld.vue │ └── Moment.vue ├── main.js ├── router │ └── index.js ├── utils │ ├── common.js │ ├── constant.js │ └── http.js └── views │ ├── About.vue │ ├── Home.vue │ ├── Iframe.vue │ ├── Index.vue │ └── Video.vue └── vue.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://pic1.zhimg.com/80/v2-9412528407ef564b20ac94a4c1b922a3_720w.jpg) 2 | 3 | # 开眼视频 vue 高仿版 4 | > 「开眼」是一款充满设计感的精品短视频应用。汇聚全球优质的短视频内容,推荐创意的短视频作品,从视觉到脑洞,带给用户全方位的惊喜与享受。 5 | 6 | [开眼视频 vue 高仿版](https://github.com/mmtou/eyepetizer_vue) 是基于「开眼」非开放 API 、使用 Vue + Vant 框架搭建的 H5 高仿版。(后续会发布 Flutter 版本,敬请期待~) 7 | 8 | 项目源码: [https://github.com/mmtou/eyepetizer_vue](https://github.com/mmtou/eyepetizer_vue) 9 | 10 | ## 预览 11 | 12 | 13 | 14 | ## 开发目的 15 | 1. Vue + Vant 实践采坑 16 | 2. 后面开发 Flutter 版本,做个对比 17 | 3. 放假在家实在无聊😏 18 | 19 | ## 技术栈 20 | 1. 使用 Vue 作为基础框架 21 | > 渐进式 JavaScript 框架 22 | 23 | 2. 使用 Vant 作为 UI 框架 24 | > 轻量、可靠的移动端 Vue 组件库 25 | 26 | ## 采坑 27 | 1. 使用 `vue-router` 时,当使用路由参数方式同一个页面跳转时,**组件的生命周期钩子不会再被调用**。 28 | 29 | 30 | > https://router.vuejs.org/zh/guide/essentials/dynamic-matching.html#响应路由参数的变化 31 | 32 | 2. 当你发布后需要二级目录访问时,需要修改`router-->index.js`;修改`nginx`配置 33 | 34 | 35 | 36 | ## 实现功能 37 | - [x] 首页 38 | - [x] 分类查询 39 | - [x] 视频详情 40 | - [x] 相关推荐 41 | - [x] 查询评论 42 | - [ ] 登录 43 | - [ ] 评论 44 | 45 | ## 感谢 46 | - [感谢「开眼」团队提供这么优秀的视频推荐平台](https://www.kaiyanapp.com/) 47 | - [感谢「YJQ」提供开眼视频API分析](https://github.com/1136535305/Eyepetizer/wiki/开眼-API-接口分析) 48 | 49 | ## 小工具 50 | 1. [carbon](https://carbon.now.sh/) 一款在线 代码生成图片 的工具 51 | 52 | ## 本地运行 53 | ```shell 54 | git clone https://github.com/mmtou/eyepetizer_vue 55 | cd eyepetizer_vue 56 | npm install 57 | npm run serve 58 | ``` 59 | 60 | ## 最后 61 | 只争朝夕,不负韶华~ 62 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /demo/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmtou/eyepetizer_vue/a3749807f251788952b5d76bc9bd66c0fa8a92f0/demo/images/1.png -------------------------------------------------------------------------------- /demo/images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmtou/eyepetizer_vue/a3749807f251788952b5d76bc9bd66c0fa8a92f0/demo/images/2.png -------------------------------------------------------------------------------- /demo/images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmtou/eyepetizer_vue/a3749807f251788952b5d76bc9bd66c0fa8a92f0/demo/images/3.png -------------------------------------------------------------------------------- /demo/images/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmtou/eyepetizer_vue/a3749807f251788952b5d76bc9bd66c0fa8a92f0/demo/images/4.png -------------------------------------------------------------------------------- /demo/images/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmtou/eyepetizer_vue/a3749807f251788952b5d76bc9bd66c0fa8a92f0/demo/images/5.png -------------------------------------------------------------------------------- /demo/images/d1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmtou/eyepetizer_vue/a3749807f251788952b5d76bc9bd66c0fa8a92f0/demo/images/d1.png -------------------------------------------------------------------------------- /demo/images/d2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmtou/eyepetizer_vue/a3749807f251788952b5d76bc9bd66c0fa8a92f0/demo/images/d2.png -------------------------------------------------------------------------------- /demo/images/d3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmtou/eyepetizer_vue/a3749807f251788952b5d76bc9bd66c0fa8a92f0/demo/images/d3.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eyepetizer_vue", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build" 8 | }, 9 | "dependencies": { 10 | "axios": "^0.19.2", 11 | "core-js": "^3.4.4", 12 | "vant": "^2.4.3", 13 | "vue": "^2.6.10", 14 | "vue-clipboard2": "^0.3.1", 15 | "vue-router": "^3.1.3" 16 | }, 17 | "devDependencies": { 18 | "@vue/cli-plugin-babel": "^4.1.0", 19 | "@vue/cli-plugin-router": "^4.1.0", 20 | "@vue/cli-service": "^4.1.0", 21 | "babel-plugin-import": "^1.13.0", 22 | "less": "^3.0.4", 23 | "less-loader": "^5.0.0", 24 | "postcss-px-to-viewport": "^1.1.1", 25 | "vue-template-compiler": "^2.6.10" 26 | }, 27 | "browserslist": [ 28 | "> 1%", 29 | "last 2 versions" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmtou/eyepetizer_vue/a3749807f251788952b5d76bc9bd66c0fa8a92f0/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 开眼视频-vue高仿版 10 | 11 | 12 | 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 38 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmtou/eyepetizer_vue/a3749807f251788952b5d76bc9bd66c0fa8a92f0/src/assets/logo.png -------------------------------------------------------------------------------- /src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 42 | 43 | 44 | 60 | -------------------------------------------------------------------------------- /src/components/Moment.vue: -------------------------------------------------------------------------------- 1 | 184 | 185 | 312 | 313 | 692 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import Vant from 'vant'; 5 | import { Lazyload } from 'vant'; 6 | import 'vant/lib/index.css'; 7 | import {get, post} from '@/utils/http.js'; 8 | import VueClipboard from 'vue-clipboard2' 9 | 10 | Vue.config.productionTip = false 11 | 12 | Vue.use(Vant); 13 | Vue.use(Lazyload); 14 | Vue.use(VueClipboard) 15 | 16 | Vue.prototype.$post = post; 17 | Vue.prototype.$get = get; 18 | 19 | new Vue({ 20 | router, 21 | render: h => h(App) 22 | }).$mount('#app') 23 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import Index from '@/views/Index.vue' 4 | import Iframe from '@/views/Iframe.vue' 5 | import Video from '@/views/Video.vue' 6 | 7 | Vue.use(VueRouter) 8 | 9 | const routes = [{ 10 | path: '/', 11 | name: 'index', 12 | component: Index, 13 | meta: { 14 | keepAlive: true 15 | } 16 | }, 17 | { 18 | path: '/video/:id', 19 | name: 'video', 20 | component: Video 21 | }, 22 | { 23 | path: '/iframe', 24 | name: 'iframe', 25 | component: Iframe 26 | } 27 | ] 28 | 29 | const router = new VueRouter({ 30 | mode: 'history', 31 | // base: process.env.BASE_URL, 32 | base: '/eyepetizer/', 33 | routes 34 | }) 35 | 36 | export default router 37 | -------------------------------------------------------------------------------- /src/utils/common.js: -------------------------------------------------------------------------------- 1 | import { CONSTANT } from './constant.js'; 2 | 3 | // 拼接url 4 | export function getUrl(url) { 5 | let temp = url.replace(CONSTANT.host, ''); 6 | let result; 7 | if (temp.indexOf('?') >= 0) { 8 | result = [temp, '&udid=', CONSTANT.udid]; 9 | } else { 10 | result = [temp, '?udid=', CONSTANT.udid]; 11 | } 12 | result.push('&vc=580&deviceModel=ONEPLUS%20A6000'); 13 | return result.join(''); 14 | } 15 | -------------------------------------------------------------------------------- /src/utils/constant.js: -------------------------------------------------------------------------------- 1 | export const CONSTANT = { 2 | host: 'http://baobab.kaiyanapp.com', 3 | udid: '3e7ee30c6fc0004a773dc33b0597b5732b145c04' 4 | } 5 | -------------------------------------------------------------------------------- /src/utils/http.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import router from '../router' 3 | import { 4 | Toast 5 | } from 'vant'; 6 | 7 | axios.defaults.timeout = 5000; 8 | axios.defaults.baseURL = ''; 9 | 10 | //http request 拦截器 11 | axios.interceptors.request.use( 12 | config => { 13 | if (!config.params.hideLoading) { 14 | Toast.loading({ 15 | message: '加载中...', 16 | forbidClick: true, 17 | duration: 0 18 | }); 19 | } 20 | config.headers = { 21 | 'Content-Type': 'application/json' 22 | } 23 | return config; 24 | }, 25 | error => { 26 | return Promise.reject(err); 27 | } 28 | ); 29 | 30 | //http response 拦截器 31 | axios.interceptors.response.use( 32 | response => { 33 | Toast.clear(); 34 | const data = response.data; 35 | return data; 36 | }, 37 | error => { 38 | Toast.clear(); 39 | const status = error.response.status; 40 | if (status == 401) { 41 | const current = router.currentRoute.fullPath; 42 | if (current != '/login') { 43 | router.push(`/login?redirect=${current}`) 44 | } 45 | } else if (status == 500) { 46 | Toast.fail('服务器异常'); 47 | } else if (status != 200) { 48 | Toast.fail('请检查请求是否正确'); 49 | } 50 | return Promise.reject(error) 51 | } 52 | ) 53 | 54 | /** 55 | * 封装get方法 56 | * @param url 57 | * @param data 58 | * @returns {Promise} 59 | */ 60 | 61 | export function get(url, params = {}) { 62 | return new Promise((resolve, reject) => { 63 | axios.get(url, { 64 | params: params 65 | }) 66 | .then(response => { 67 | resolve(response); 68 | }) 69 | .catch(err => { 70 | reject(err) 71 | }) 72 | }) 73 | } 74 | 75 | 76 | /** 77 | * 封装post请求 78 | * @param url 79 | * @param data 80 | * @returns {Promise} 81 | */ 82 | 83 | export function post(url, data = {}) { 84 | return new Promise((resolve, reject) => { 85 | axios.post(url, data) 86 | .then(response => { 87 | resolve(response); 88 | }, err => { 89 | reject(err) 90 | }) 91 | }) 92 | } 93 | -------------------------------------------------------------------------------- /src/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /src/views/Iframe.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 25 | 26 | 44 | -------------------------------------------------------------------------------- /src/views/Index.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 104 | 105 | > 123 | -------------------------------------------------------------------------------- /src/views/Video.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 99 | 100 | 181 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const autoprefixer = require("autoprefixer"); 2 | const pxtoviewport = require("postcss-px-to-viewport"); 3 | 4 | module.exports = { 5 | outputDir: "dist", 6 | publicPath: process.env.NODE_ENV === "production" ? "./" : "/", 7 | css: { 8 | loaderOptions: { 9 | postcss: { 10 | plugins: [ 11 | autoprefixer(), 12 | pxtoviewport({ 13 | viewportWidth: 375 14 | }) 15 | ] 16 | } 17 | } 18 | }, 19 | devServer: { 20 | proxy: { 21 | '^/api': { 22 | target: 'http://baobab.kaiyanapp.com', 23 | ws: true, 24 | changeOrigin: true, 25 | pathRewrite: { 26 | '^/api': '/api' 27 | } 28 | } 29 | } 30 | } 31 | } 32 | --------------------------------------------------------------------------------