├── .browserslistrc ├── public ├── favicon.ico └── index.html ├── postcss.config.js ├── src ├── assets │ └── logo.png ├── static │ ├── video │ │ └── icon_play.png │ └── css │ │ └── iconfont.css ├── store.js ├── router.js ├── main.js ├── App.vue ├── components │ └── HelloWorld.vue └── views │ └── Home.vue ├── babel.config.js ├── .babelrc ├── .gitignore ├── .eslintrc.js ├── README.md ├── package.json └── vue.config.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superliebe/fangdouyin/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | }; 6 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superliebe/fangdouyin/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /src/static/video/icon_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superliebe/fangdouyin/HEAD/src/static/video/icon_play.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ], 5 | sourceType: 'unambiguous' 6 | } 7 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "plugins": [ 4 | "@babel/plugin-transform-runtime" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /src/store.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex from "vuex"; 3 | 4 | Vue.use(Vuex); 5 | 6 | export default new Vuex.Store({ 7 | state: {}, 8 | mutations: {}, 9 | actions: {} 10 | }); 11 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | extends: ["plugin:vue/essential"], 7 | rules: { 8 | "no-console": process.env.NODE_ENV === "production" ? "error" : "off", 9 | "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off" 10 | }, 11 | parserOptions: { 12 | parser: "babel-eslint" 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Router from "vue-router"; 3 | import Home from "./views/Home.vue"; 4 | 5 | Vue.use(Router); 6 | 7 | export default new Router({ 8 | routes: [ 9 | { 10 | path: "/", 11 | name: "home", 12 | component: Home 13 | },{ 14 | path: "/home", 15 | name: "home", 16 | component: Home 17 | }, 18 | ] 19 | }); 20 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import App from "./App.vue"; 3 | import router from "./router"; 4 | import store from "./store"; 5 | // 引入组件样式 6 | import Vant from 'vant'; 7 | import 'vant/lib/index.css'; 8 | import './static/css/iconfont.css' 9 | 10 | import utils from 'km-vue-utils' 11 | Vue.use(utils); 12 | Vue.prototype.$utils = utils; 13 | Vue.use(Vant); 14 | 15 | 16 | Vue.config.productionTip = false; 17 | 18 | new Vue({ 19 | router, 20 | store, 21 | render: h => h(App) 22 | }).$mount("#app"); 23 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue仿抖音 2 | 3 | ## 2019年12月最新更新 4 | 新增留言功能,优化安卓微信环境境下播放不流畅问题 5 | 6 | ## 基本介绍 7 | 制作仿抖音视频列表遇到很多坑,特别是安卓微信内置浏览器,让人脑壳疼,核心代码不多 便于理解 8 | 9 | 图标css使用的事iconfot字体库,优化页面加载速度 http://at.alicdn.com/t/font_1048614_mi5i5ba1uag.css 10 | 11 | 组件用到了vant 中的swiper滑动组件 12 | 13 | ## video原生参数介绍 14 | ``` 15 | h5 原生 video 属性 16 | webkit-playsinline ios 小窗播放,使视频不脱离文本流,安卓则无效 17 | 微信内置x5内核, 18 | x5-video-player-type="h5-page" 启用H5播放器,是wechat安卓版特性,添加此属性,微信浏览器会自动将视频置为全屏 19 | x5-video-player-fullscreen="true" 全屏设置,设置为 true 是防止横屏 20 | x5-video-orientation 控制横竖屏 landscape 横屏,portrain竖屏; 默认portrain 21 | poster:封面 22 | src:播放地址 23 | loop防止播放视频结束后,显示腾讯的广告 24 | ``` 25 | ## 安装步奏 26 | ``` 27 | cnpm install 28 | ``` 29 | 30 | ### 安装后运行 31 | ``` 32 | cnpm run serve 33 | ``` 34 | 35 | ### Customize configuration 36 | See [Configuration Reference](https://cli.vuejs.org/config/). 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fangdouyin", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "core-js": "^2.6.5", 12 | "km-vue-utils": "^0.0.1", 13 | "vant": "^2.2.15", 14 | "vue": "^2.6.10", 15 | "vue-router": "^3.0.3", 16 | "vuex": "^3.0.1", 17 | "weixin-js-sdk": "^1.6.0" 18 | }, 19 | "devDependencies": { 20 | "@vue/cli-plugin-babel": "^3.1.1", 21 | "@vue/cli-plugin-eslint": "^3.1.1", 22 | "@vue/cli-service": "^3.1.1", 23 | "@vue/eslint-config-prettier": "^5.0.0", 24 | "babel-eslint": "^10.0.1", 25 | "eslint": "^5.16.0", 26 | "eslint-plugin-prettier": "^3.1.0", 27 | "eslint-plugin-vue": "^5.0.0", 28 | "node-sass": "^4.12.0", 29 | "prettier": "^1.18.2", 30 | "sass-loader": "^8.0.0", 31 | "vue-template-compiler": "^2.6.10" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | vue仿抖音 16 | 17 | 18 | 19 | 22 |
23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 88 | 89 | 97 | 98 | 99 | 115 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const resolve = dir => {return path.join(__dirname, dir)} 3 | let target = 'http://localhost:8090/'; 4 | // let target = 'https://blog.csdn.net/superKM'; 5 | if (process.env.NODE_ENV === 'production') { 6 | target = ''; 7 | } 8 | module.exports = { 9 | // 选项... 10 | publicPath: process.env.NODE_ENV === 'production' ? './' : '/',//部署服务器路径 11 | // 输出文件目录 12 | outputDir: "dist", 13 | assetsDir: "static",//放置生成的静态资源的目录 14 | indexPath: "index.html",//指定生成的 index.html 的输出路径 15 | filenameHashing: true, 16 | // pages: undefined, 17 | pages: { 18 | //pages 里配置的路径和文件名在你的文档目录必须存在 否则启动服务会报错 19 | index: { 20 | //除了 entry 之外都是可选的 21 | entry: 'src/main.js', // page 的入口,每个“page”应该有一个对应的 JavaScript 入口文件 22 | template: 'public/index.html', // 模板来源 23 | filename: 'index.html', // 在 dist/index.html 的输出 24 | title: 'Index Page', // 当使用 title 选项时,在 template 中使用:<%= htmlWebpackPlugin.options.title %> 25 | chunks: ['chunk-vendors', 'chunk-common', 'index'] // 在这个页面中包含的块,默认情况下会包含,提取出来的通用 chunk 和 vendor chunk 26 | } 27 | }, 28 | // eslint-loader 是否在保存的时候检查 29 | lintOnSave: false, 30 | runtimeCompiler: true, 31 | transpileDependencies: ['webpack-dev-server/client'], 32 | //生产环境关闭map 33 | productionSourceMap: false, 34 | crossorigin: undefined, 35 | integrity: false, 36 | // webpack配置 37 | // see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md 38 | chainWebpack: config => { 39 | config.entry.app = ['babel-polyfill', './src/main.js']; 40 | // 修复HMR 41 | config.resolve.symlinks(true); 42 | config.resolve.alias //别名 43 | .set('@', resolve('src')) // key,value自行定义,比如.set('@@', resolve('src/components')) 44 | .set('_v', resolve('src/views')) 45 | .set('vendor', resolve('src/vendor')); 46 | }, 47 | //统一配置打包插件 48 | configureWebpack: { 49 | plugins: [] 50 | }, 51 | // vue-loader 配置项 52 | // vueLoader: {}, 53 | // 生产环境是否生成 sourceMap 文件 54 | css: { 55 | // 是否使用css分离插件 ExtractTextPlugin 56 | extract: true, 57 | // 开启 CSS source maps? 58 | sourceMap: false, 59 | // css预设器配置项 60 | loaderOptions: {}, 61 | // 启用 CSS modules for all css / pre-processor files. 62 | modules: false 63 | }, 64 | // use thread-loader for babel & TS in production build 65 | // enabled by default if the machine has more than 1 cores 66 | parallel: require('os').cpus().length > 1, 67 | pwa: {}, 68 | devServer: { 69 | /** 70 | * 这一块是devServer的配置,可以参考https://webpack.js.org/configuration/dev-server/ 71 | * (可选,根据自己情况来设置) 72 | */ 73 | // 开发环境配置 74 | host: '0.0.0.0', 75 | port: 8080, 76 | https: false, 77 | hotOnly: false, 78 | open: false, //配置自动启动浏览器 79 | // 设置代理 80 | proxy: { 81 | // 如果你的前端应用和后端 API 服务器没有运行在同一个主机上,你需要在开发环境下将 API 请求代理到 API 服务器。这个问题可以通过 vue.config.js 中的 devServer.proxy 选项来配置。 82 | "/api": { 83 | //你要跨域的域名(包含host、端口号,切记:一定要带上http头); 84 | //同一个域名只能设置一次跨域,否则重复报错! 85 | target: target, 86 | ws: true, 87 | changOrigin: true, //是否跨域,设置为true;(必须) 88 | /**(可选设置----如果访问域名根目录,那这里必须设置重定向了) 89 | * 是否要把'/api'目录重定向去哪里,跟目录还是其他(可选) 90 | * 如果设置了,那在axios的路径中/article替换成https://baike.baidu.com/相当于根目录一样! 91 | * */ 92 | }, 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /src/static/css/iconfont.css: -------------------------------------------------------------------------------- 1 | @font-face {font-family: "iconfont"; 2 | src: url('//at.alicdn.com/t/font_1048614_4nq25dmhzfk.eot?t=1575364271230'); /* IE9 */ 3 | src: url('//at.alicdn.com/t/font_1048614_4nq25dmhzfk.eot?t=1575364271230#iefix') format('embedded-opentype'), /* IE6-IE8 */ 4 | url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'), 5 | url('//at.alicdn.com/t/font_1048614_4nq25dmhzfk.woff?t=1575364271230') format('woff'), 6 | url('//at.alicdn.com/t/font_1048614_4nq25dmhzfk.ttf?t=1575364271230') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ 7 | url('//at.alicdn.com/t/font_1048614_4nq25dmhzfk.svg?t=1575364271230#iconfont') format('svg'); /* iOS 4.1- */ 8 | } 9 | 10 | .iconfont { 11 | font-family: "iconfont" !important; 12 | font-size: 16px; 13 | font-style: normal; 14 | -webkit-font-smoothing: antialiased; 15 | -moz-osx-font-smoothing: grayscale; 16 | } 17 | 18 | .icon-iconfontforward:before { 19 | content: "\e606"; 20 | } 21 | 22 | .icon-fasong:before { 23 | content: "\e700"; 24 | } 25 | 26 | .icon-lianjie:before { 27 | content: "\e67a"; 28 | } 29 | 30 | .icon-gouwuche:before { 31 | content: "\e600"; 32 | } 33 | 34 | .icon-pengyouquan:before { 35 | content: "\e601"; 36 | } 37 | 38 | .icon-shoucang:before { 39 | content: "\e603"; 40 | } 41 | 42 | .icon-zanwupinglun:before { 43 | content: "\e646"; 44 | } 45 | 46 | .icon-weixin:before { 47 | content: "\e7b0"; 48 | } 49 | 50 | .icon-gouwuche1:before { 51 | content: "\e63e"; 52 | } 53 | 54 | .icon-liuyan:before { 55 | content: "\e639"; 56 | } 57 | 58 | .icon-jiahao:before { 59 | content: "\e75e"; 60 | } 61 | 62 | .icon-duihao:before { 63 | content: "\e722"; 64 | } 65 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 175 | 591 | 1218 | --------------------------------------------------------------------------------