zoukankan      html  css  js  c++  java
  • VUE实践经典记录(持续更新)

    上下固定,中间滚动布局(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{
             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 {
             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请求进行处理

    src/utils/request.js
    import axios from 'axios'
    import {Notification, MessageBox} from 'element-ui'
    import store from '@/store'
    import {getToken} from '@/utils/auth'
    
    axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
    // 创建axios实例
    const service = axios.create({
      // axios中请求配置有baseURL选项,表示请求URL公共部分
      baseURL: process.env.VUE_APP_BASE_API,
      // 超时
      timeout: 10000
    })
    // request拦截器
    service.interceptors.request.use(
      config => {
        if (getToken()) {
          config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
        }
        return config
      },
      error => {
        Promise.reject(error)
      }
    )
    
    // 响应拦截器
    service.interceptors.response.use(res => {
        const code = res.data.code
        if (code === 401) {
          MessageBox.confirm(
            '登录状态已过期,您可以继续留在该页面,或者重新登录',
            '系统提示',
            {
              confirmButtonText: '重新登录',
              cancelButtonText: '取消',
              type: 'warning'
            }
          ).then(() => {
            store.dispatch('LogOut').then(() => {
              location.reload() // 为了重新实例化vue-router对象 避免bug
            })
          })
        } else if (code !== 200) {
          Notification.error({
            title: res.data.msg
          })
          return Promise.reject('error')
        } else {
          return res.data
        }
      },
      error => {
        Message({
          message: error.message,
          type: 'error',
          duration: 5 * 1000
        })
        return Promise.reject(error)
      }
    )
    
    export default service
    
    src/api.js
    import request from '@/utils/request'
    // AXIOS GET请求
    
    // get
    export function listConfig(query) {
      return request({
        url: '/system/config/list',
        method: 'get',
        params: query
      })
    }
    // post
    export function addConfig(data) {
      return request({
        url: '/system/config',
        method: 'post',
        data: data
      })
    }
    

      

    路由的其他一些配置

    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>

     

    对函数进行封装全局使用

    src/utils/global.js //公共方法写在这
    exports.install = function (Vue, options) {
      /**
       * 对小数位进行格式化
       * @data 数据
       * @num 格式位数
       * */
      Vue.filter('decimalPlaceFormat', function (data, num) {
        if (!(data && num)) return ''
        return Number(data).toFixed(num)
      });
    }
    
    src/main.js //引用安装
    import global from './utils/global'
    Vue.use(global)
    

    对指令封装全局使用

    src/directive/hasPermiss.js
    /**
    * 按钮权限控制
    * */
    
    import store from './../store'
    export default {
      inserted(el,binding) {
        const {value} = binding;
        const btnPermiss = store.getters.btnPermiss;
        let status =  btnPermiss.some(item => item == value);
        if(!status){
          el.parentNode && el.parentNode.removeChild(el);
        }
      }
    }
    
    
    src/directive/index.js
    import hasPermiss from './hasPermiss'
    const install = function(Vue) {
      Vue.directive('hasPermiss',hasPermiss)
    }
    if (window.Vue) {
      window['hasPermiss'] = hasPermiss;
      Vue.use(install);
    }
    export default install
    
    src/main.js
    import install from './directive'
    Vue.use(global);
    

      

    VUEX模块使用

    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 安装插件
    
  • 相关阅读:
    c.vim
    Ubuntu18.04重装指南
    [TJOI2017]城市 【树的直径+暴力+优化】
    [Bzoj3696]化合物【暴力+树形Dp】
    [JLOI2015]战争调度【暴力+树形Dp】
    [Bzoj3743][Coci2015] Kamp【换根Dp】
    [POI2017]Sabota【观察+树形Dp】
    [CQOI2009]叶子的染色【性质+树形Dp】
    COCI2014/2015 Contest#1 D MAFIJA【基环树最大独立点集】
    [牛客网] 推箱子【离散,线段树区间覆盖】
  • 原文地址:https://www.cnblogs.com/yz-blog/p/11387280.html
Copyright © 2011-2022 走看看