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 安装插件
    
  • 相关阅读:
    golang 数据结构 优先队列(堆)
    leetcode刷题笔记5210题 球会落何处
    leetcode刷题笔记5638题 吃苹果的最大数目
    leetcode刷题笔记5637题 判断字符串的两半是否相似
    剑指 Offer 28. 对称的二叉树
    剑指 Offer 27. 二叉树的镜像
    剑指 Offer 26. 树的子结构
    剑指 Offer 25. 合并两个排序的链表
    剑指 Offer 24. 反转链表
    剑指 Offer 22. 链表中倒数第k个节点
  • 原文地址:https://www.cnblogs.com/yz-blog/p/11387280.html
Copyright © 2011-2022 走看看