上下固定,中间滚动布局(FLEX)
<div id="app"> <div class="header"></div> <div class="views"></div> <div class="footer"></div> </div> <style> #app{display: flex;flex-direction: column;height: 100%;} .views{flex: 1; overflow-y: scroll;-webkit-overflow-scrolling: touch;} /*-webkit-overflow-scrolling: touch; 解决苹果手机下网页滑动不顺畅问题*/ .header{} /*高度随意设置*/ .footer{} /*高度随意设置*/ </style>
Vue插件封装(loading实例)
src/omponents/loading/Loading.vue <template> <div class="loading" v-show="show"> <i class="i-loading"></i> </div> </template> <script> export default { props: { show: Boolean } } </script> <style lang="scss" scoped> .loading{ width: 200px; height: 200px; position: fixed; left: 0; right: 0; bottom: 0; top: 0; margin: auto; border-radius: 6px; background: rgba(0,0,0,0.6); display: flex; justify-content: center; align-items: center; z-index: 999; } .i-loading { width: 90px; height: 90px; display: inline-block; vertical-align: middle; -webkit-animation: loading 1s steps(12, end) infinite; animation: loading 1s steps(12, end) infinite; background: transparent url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAiIGhlaWdodD0iMTIwIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgxMDB2MTAwSDB6Ii8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTlFOUU5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTMwKSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iIzk4OTY5NyIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgzMCAxMDUuOTggNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjOUI5OTlBIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDYwIDc1Ljk4IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0EzQTFBMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSg5MCA2NSA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNBQkE5QUEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoMTIwIDU4LjY2IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0IyQjJCMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgxNTAgNTQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjQkFCOEI5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDE4MCA1MCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDMkMwQzEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTE1MCA0NS45OCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDQkNCQ0IiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTEyMCA0MS4zNCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNEMkQyRDIiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTkwIDM1IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0RBREFEQSIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgtNjAgMjQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTJFMkUyIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKC0zMCAtNS45OCA2NSkiLz48L3N2Zz4=) no-repeat; background-size: 100%; } @keyframes loading { 0% { -webkit-transform: rotate3d(0, 0, 1, 0deg); transform: rotate3d(0, 0, 1, 0deg); } 100% { -webkit-transform: rotate3d(0, 0, 1, 360deg); transform: rotate3d(0, 0, 1, 360deg); } } </style> src/omponents/loading/index.js <script> import LoadingComponent from './loading' let $vm export default { install (Vue, options) { if (!$vm) { const LoadingPlugin = Vue.extend(LoadingComponent) $vm = new LoadingPlugin({ el: document.createElement('div') }) console.log($vm) } $vm.show = false let loading = { show (text) { $vm.show = true $vm.text = text document.body.appendChild($vm.$el) }, hide () { $vm.show = false } } if (!Vue.$loading) { Vue.$loading = loading } Vue.mixin({ created () { this.$loading = Vue.$loading } }) } } //使用 import Loading from '@/components/loading/index.js' //loading 插件 Vue.use(Loading) //使用loading插件 Vue.$loading.show() //显示 Vue.$loading.hide() //隐藏 </script>
axios全局路由拦截及结合promise对axios请求进行处理
/* 状态码 200:操作成功 400:请求无法处理,检查参数是否正确 401:未通过身份验证 402: 账号在别处登录 403:已通过身份验证,但不具备访问权限 404:请求的资源不存在 500:已收到请求,服务器处理发生了意外 503:服务器停止工作 */ import Vue from 'vue' import axios from 'axios' import Qs from 'qs' import 'vuex' import store from './../vuex/store' //项目数据仓库 import router from './../router/index' //路由文件 import Loading from '@/components/loading/index.js' //loading 插件 Vue.use(Loading) //使用loading插件 // 基地址 const baseUrl = 'xxxx' axios.defaults.withCredentials = true // 添加请求拦截器 axios.interceptors.request.use(function (config) { config.headers.Authorization = JSON.stringify(store.state.user) !== '{}' ? store.state.user.token : '' //把拿到的token放到请求头部 Vue.$loading.show() //每个请求都增加loading效果 return config }, function (error) { return Promise.reject(error) }) // 添加响应拦截器 axios.interceptors.response.use(function (response) { // console.log(response) Vue.$loading.hide() //服务器响应后把loading隐藏掉 //后面根据不同的状态码,可做不同的操作 switch (response.data.code) { case 401: store.dispatch('setUser', {}) //未通过验证,把store里的数据清空 break case 402: store.dispatch('setUser', {}) //账号在别处登录,把store里的数据清空之后,跳转到登录页面 router.push({ name: 'signIn' }) break case 403: router.push({ name: 'vipRecharge', query: { type: 'life' } }) //已通过身份验证,但不具备访问权限,跳转到充值页面 break case 404: break case 500: break case 503: break default: } return response }, function (error) { // 对响应错误做点什么 return Promise.reject(error) }) // AXIOS GET请求 export const videoIndex = function () { return new Promise((resolve, reject) => { axios.get(`${baseUrl}/videoIndex`) .then(res => resolve(res.data)) .catch(res => reject(res)) }) } // AXIOS POST请求 export const videoCollect = function (id) { return new Promise((resolve, reject) => { let data = { vid: id } axios({ method: 'post', url: `${baseUrl}/videoCollect`, data: Qs.stringify(data) }) .then(res => resolve(res.data)) .catch(res => reject(res)) }) }
路由的其他一些配置
router.beforeEach((to, from, next) => { // 动态更改页面title if (to.meta.title) { document.title = to.meta.title } // 验证是否需要登陆 if (to.meta.requireAuth && JSON.stringify(store.state.user) === '{}') { next({ name: 'signIn' }) } // 如果登录状态进入登录页面则,返回到个人中心页面 if (JSON.stringify(store.state.user) !== '{}') { if (to.name === 'signIn' || to.name === 'resetPassword' || to.name === 'mobileLogin') { next({ name: 'personal', query: { type: 'records' } }) } } next() })
解决移动端click300ms问题
安装 npm install fastclick --save 使用 import fastclick from 'fastclick' fastclick.attach(document.body)
Vue父子组件通讯
父向子传递参数 Parent.vue(父组件) <template> <div> <Child :name="name"></Child> </div> </template> <script> import Child from './Child' export default{ components:{ Child }, data(){ return{ name:'hello' } } } </script> Child.vue(子组件) <template> <div> <!-- 这里的name接收了父组件传过来的参数,这里会变成hello --> {{name}} </div> </template> <script> export default{ props:{ name:String } } </script> 子向父传递参数 Child.vue(子组件) <template> <div> <button @click="toParentMsg()">我要向父节点传递参数</button> </div> </template> <script> export default{ method:{ toParentMsg(){ this.$emit('listenToChildEvent','我是要向父组件传送的数据') //listenToChildEvent 自定义事件,后面需要再父组件接收这个自定义事件 } } } </script> Parent.vue(父组件) <template> <div> <Child @listenToChildEvent = "receiveChildMsg"></Child> </div> </template> <script> import Child from './Child' export default{ components:{ Child }, data(){ }, method:{ receiveChildMsg(val){ console.log(val) //我是要向父组件传送的数据 } } } </script>
Vuex数据操作及数据持久化
使用vuex-persistedstate插件 const store = new Vuex.Store({ state: { // 用户信息 user: {}, // 分类页数据筛选 videoListFilterTerm: { catId: 0, courseId: 0, software: 0, diff: 0, sort: 3, page: 1 } }, //获取state数据 getters: { getUser (state) { return state.user } }, //操作state数据 mutations: { setUser (state, user) { state.user = user }, setVideoListFilterTerm (state, videoListFilterTerm) { state.videoListFilterTerm = videoListFilterTerm } }, //触发mutations函数 actions: { setUser ({ commit }, user) { commit('setUser', user) }, setVideoListFilterTerm ({ commit }, videoListFilterTerm) { commit('setVideoListFilterTerm', videoListFilterTerm) } }, //插件配置 plugins: [createPersistedState({ storage: window.localStorage, reducer (val) { return { user: val.user } } })] })
Vue m3u8视频播放配置
播放m3u8视频需要用到 videojs-contrib-hls插件 安装 npm install videojs-contrib-hls --save 导入import 'videojs-contrib-hls'
Vue-router 实现模块化加载
使用该方式导入组件,打包模块会自动把组件进行模块化打包 const xxx = () => import('@/views/xxx')
Vue路由切换增加动画效果
90sheji-video/src/App.vue <template> <div id="app"> <transition name="fade" mode="out-in"> <router-view /> </transition> </div> </template> <script> export default { name: 'App' } </script> src/components/layout/Layout.vue <template> <div class="layout flex"> <Header/> <transition name="fade-transform" mode="out-in"> <keep-alive> <router-view :key="key"/> </keep-alive> </transition> <Footer/> </div> </template> <script> import Footer from '@/components/common/Footer' import Header from '@/components/common/Header' export default { data () { return { catId: '' } }, components: { Footer, Header }, computed: { key () { return this.$route.name ? this.$route.name : this.$route.fullPath } } } </script> <style> /*********************动画·start**************************/ /* fade */ .fade-enter-active, .fade-leave-active { transition: opacity 0.2s; } .fade-enter, .fade-leave-active { opacity: 0; } /* fade-transform */ .fade-transform-leave-active, .fade-transform-enter-active { transition: all 0.2s; } .fade-transform-enter { opacity: 0; transform: translateX(-20px); } .fade-transform-leave-to { opacity: 0; transform: translateX(20px); } /* breadcrumb transition */ .breadcrumb-enter-active, .breadcrumb-leave-active { transition: all 0.2s; } .breadcrumb-enter, .breadcrumb-leave-active { opacity: 0; transform: translateX(20px); } .breadcrumb-move { transition: all 0.2s; } .breadcrumb-leave-active { position: absolute; } /*********************动画·end**************************/ </style> 组件切换有两种情况,一种是兄弟与兄弟组件切换,一种是子组件与父组件之间切换,所以这里转场动画用的不一样,所以贴出了两个组件用法 <keep-alive> 增加这个标签表示组件可以被缓存起来,强烈加上 <router-view :key="key"/> 前面用了组件缓存,所以路由视图的key一定要加上,不然路由和页面有些会不匹配
vue使用官方脚手架打包上线配置
/config/index.js build: { // Template for index.html index: path.resolve(__dirname, '../dist/index.html'),//入口文件 // Paths assetsRoot: path.resolve(__dirname, '../dist'),//编译后所有需要部署的文件都放到了这里 assetsSubDirectory: 'public',//静态资源存放的文件目录 assetsPublicPath: './',// ./是相对路径,/是绝对路径,这里改为相对路径,不然打包后上线图片访问不了 productionSourceMap: true,//是否开启SourceMap压缩 devtool: '#source-map', productionGzip: false,//是否开启Gzip压缩 productionGzipExtensions: ['js', 'css'],//Gzip压缩 bundleAnalyzerReport: process.env.npm_config_report }
后端解决跨域配置
resp.setHeader("Access-Control-Allow-Origin", "*"); resp.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
package.json文件中dependencies与devDependencies的区别
dependencies:打包上线需要用到的插件 使用npm inatall --save xxx 安装插件 devDependencies:开发环境需要用到的插件 使用npm install --save-dev xxx 安装插件
来源:https://www.cnblogs.com/yz-blog/p/11387280.html