zoukankan      html  css  js  c++  java
  • 【vue】常见开发知识点与问题整理(持续更新)

    1.vue双向数据绑定vuex中的state

    在vue中, 不允许直接绑定vuex的值到组件中, 若是直接使用, 则会报错 have no setter

    方法一: 使用get和set

    // 在从组件的computed中
    computed: {
        user: {
            get() {
              return this.$store.state.user
            },
            set(v) {
              // 使用vuex中的mutations中定义好的方法来改变
              this.$store.commit('USER', v)
            }
        }
    }
    // 在组件中就可以使用
    <input v-modle="user" />

    方法二: 使用watch

    // 在组件中绑定
    <input v-modle="user" />
    
    // 在computed中获取vuex的值
    computed: {
      ...mapState( { user: state => state.user } )
    }
    
    // 在组件的watch中观测
    watch: {
      'user': {
          deep: true,
          handler(value) {
            // 使用vuex中的mutations中定义好的方法来改变
              this.$store.commit('USER', value)
          }
      }
    }

     2.(webpack)vue-cli构建的项目如何设置每个页面的title

    在路由里每个都添加一个meta:

    [{
        path:'/login',
        meta: {
          title: '登录页面'
        },
        component:'login'
    }]

    钩子函数,在main.js中添加如下代码:

    router.beforeEach((to, from, next) => {
      window.document.title = to.meta.title;
      next()
    })

    3.vue项目中使用axios上传图片等文件

    通过form表单提交,html代码如下:

    <input name="file" type="file" accept="image/png,image/gif,image/jpeg" @change="update"/>

    JS代码:

    import axios from 'axios'
    
    update(e) {
        let file = e.target.files[0]
        let param = new FormData(); // 创建form对象
        param.append('file', file); // 通过append向form对象添加数据
        param.append('chunk', '0'); // 添加form表单中其他数据
        let config = { // 添加请求头
            headers: {
                'Content-Type': 'multipart/form-data'
            }
        };
        axios.post('http://172.19.26.60:8080/user/headurl', param, config)
        .then(response => {
            if (response.data.code === 200) {
                this.ImgUrl = response.data.data;
            }
        })
    }

     4.qs.stringify() 和JSON.stringify()的区别、vux中使用post提交表单数据需要qs库序列化

    qs库的npm地址:https://www.npmjs.com/package/qs

    功能虽然都是序列化。假设我要提交的数据如下:

    var a = {name:'hehe',age:10};

    qs.stringify序列化结果如下:name=hehe&age=10

    而JSON.stringify序列化结果如下:"{"a":"hehe","age":10}"

    vux中使用post提交表单数据:

    this.$http.post(this.$sign.config.url.loginUrl,this.$qs.stringify({
        "phone":this.phoneNumber,
        "vCode":this.loginCode,
        "smsCode":this.phoneCode    
        })
    )
    .then(response=>{
        console.log(response.data);
        if(response.data.httpCode == 200){
            
        }else{
            
        }
    }) 

    在firebug中可以看到传递的参数:phone=15210275239&vCode=8vsd&smsCode=1534

    在vue中使用axios:

    this.$axios.post(loginUrl, {
        "email": this.email,
        "password": this.password
    }, {
        transformRequest: (data) => {
            return this.$qs.stringify(data)
        },
    }).then(res => {
        if(res.data.resultCode == RESULT_CODE_SUCCESS){
            console.log('登录成功');
            this.$router.push({name:"home"})
        }else{
            console.log('登录失败');
        }
    }).catch(err => {
        console.log('登登录出现错误');
    })

     5.vue全局实现的setCookie、getCookie、delCookie

    //设置cookie,增加到vue实例方便全局调用
    Vue.prototype.setCookie = (c_name, value, expiredays) => {
      var exdate = new Date();    
      exdate.setDate(exdate.getDate() + expiredays);    
      document.cookie = c_name + "=" + escape(value) + ((expiredays == null) ? "" : ";expires=" + exdate.toGMTString());
    }
    
    //获取cookie
    Vue.prototype.getCookie = (name) => {
        var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
        if (arr = document.cookie.match(reg)){
            return (arr[2]);
        }   
        return null;   
    }
    
    //删除cookie
    Vue.prototype.delCookie =(name) => {
        var exp = new Date();
        exp.setTime(exp.getTime() - 1);
        var cval = this.getCookie(name);
        if (cval != null){
            document.cookie = name + "=" + cval + ";expires=" + exp.toGMTString();
        }     
    }

     6.webpack proxyTable 代理跨域

    webpack 开发环境可以使用proxyTable 来代理跨域,生产环境的话可以根据各自的服务器进行配置代理跨域就行了。在我们的项目config/index.js 文件下可以看到有一个proxyTable的属性,我们对其简单的改写:

    proxyTable: {
        '/api': {
            target: 'http://api.douban.com/v2',
            changeOrigin: true,
            pathRewrite: {
                '^/api': ''
            }
        }
    }

    这样当我们访问localhost:8080/api/movie的时候 其实我们访问的是http://api.douban.com/v2/movie这样便达到了一种跨域请求的方案。

    当然我们也可以根据具体的接口的后缀来匹配代理,如后缀为.shtml,代码如下:

    proxyTable: {
        '**/*.shtml': {
            target: 'http://192.168.198.111:8080/abc',
            changeOrigin: true
        }
    }

    可参考地址:

     7.vue和mintui-Loadmore结合实现下拉刷新,上拉加载 (待优化)

    mintui是饿了么团队针对vue开发的移动端组件库,方便实现移动端的一些功能,这里只用了Loadmore功能实现移动端的上拉分页刷新,下拉加载数据.
    mintui官网:http://mint-ui.github.io/#!/zh-cn

    <template>  
      <div class="main-body" :style="{'-webkit-overflow-scrolling': scrollMode}">  
        <v-loadmore :top-method="loadTop" :bottom-method="loadBottom" :bottom-all-loaded="allLoaded" :auto-fill="false" ref="loadmore">  
          <ul class="list" v-for="(val, key) in pageList">  
            <li>  
              <div>我是小11</div>  
              <div>我是小11</div>  
            </li>  
          </ul>  
        </v-loadmore>  
      </div>  
    </template>  
    <script>  
      import {Loadmore} from 'mint-ui';  
      export default {  
        data:function() {  
          return {  
            searchCondition:{  //分页属性  
              pageNo:"1",  
              pageSize:"10"  
            },  
            pageList:[],  
            allLoaded: false, //是否可以上拉属性,false可以上拉,true为禁止上拉,就是不让往上划加载数据了  
            scrollMode:"auto" //移动端弹性滚动效果,touch为弹性滚动,auto是非弹性滚动  
          }  
        },  
        components: {  
          'v-loadmore':Loadmore  // 为组件起别名,vue转换template标签时不会区分大小写,例如:loadMore这种标签转换完就会变成loadmore,容易出现一些匹配问题  
                                  // 推荐应用组件时用a-b形式起名  
        },  
        mounted(){  
          this.loadPageList();  //初次访问查询列表  
        },  
        methods: {  
          loadTop:function() { //组件提供的下拉触发方法  
            //下拉加载  
            this.loadPageList();  
            this.$refs.loadmore.onTopLoaded();// 固定方法,查询完要调用一次,用于重新定位  
          },  
          loadBottom:function() {  
            // 上拉加载  
            this.more();// 上拉触发的分页查询  
            this.$refs.loadmore.onBottomLoaded();// 固定方法,查询完要调用一次,用于重新定位  
          },  
          loadPageList:function (){  
              // 查询数据  
            this.api.PageList(this.searchCondition).then(data =>{  
              // 是否还有下一页,加个方法判断,没有下一页要禁止上拉  
              this.isHaveMore(data.result.haveMore);  
              this.pageList = data.result.pageList;  
              this.$nextTick(function () {  
                // 原意是DOM更新循环结束时调用延迟回调函数,大意就是DOM元素在因为某些原因要进行修改就在这里写,要在修改某些数据后才能写,  
                // 这里之所以加是因为有个坑,iphone在使用-webkit-overflow-scrolling属性,就是移动端弹性滚动效果时会屏蔽loadmore的上拉加载效果,  
                // 花了好久才解决这个问题,就是用这个函数,意思就是先设置属性为auto,正常滑动,加载完数据后改成弹性滑动,安卓没有这个问题,移动端弹性滑动体验会更好  
                this.scrollMode = "touch";  
              });  
            });  
          },  
          more:function (){  
              // 分页查询  
            this.searchCondition.pageNo = parseInt(this.searchCondition.pageNo) + 1;  
            this.api.loadPageList(this.searchCondition).then(data=>{  
              this.pageList = this.pageList.concat(data.result.pageList);  
              this.isHaveMore(data.result.haveMore);  
            });  
          },  
          isHaveMore:function(isHaveMore){  
            // 是否还有下一页,如果没有就禁止上拉刷新  
            this.allLoaded = true; //true是禁止上拉加载  
            if(isHaveMore){  
              this.allLoaded = false;  
            }  
          }  
        }  
      }  
    </script>

    PS:有个坑一定要注意就是注释里说的iPhone里loadmore和-webkit-overflow-scrolling属性冲突无法上拉问题

    可参考另外一个插件,没有使用过,《简单灵活且强大的Vue下拉刷新组件:vue-pull-to》

    8.vue非父子组件通信

    如果2个组件不是父子组件那么如何通信呢?这时可以通过eventHub来实现通信。所谓eventHub就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。

    方式一
    组件1触发:

    <div @click="eve"></div>
    methods: {
        eve() {
            Hub.$emit('change','hehe'); //Hub触发事件
        }
    }

    组件2接收:

    created() {
        Hub.$on('change', (msg) => { //Hub接收事件
            this.msg = msg;
        });
    }

     可参考:vue非父子组件怎么进行通信

    方式二

    把中转站数据存放到根实例下面,如下:

    // 根组件(this.$root)
    new Vue({
     el: '#app',
     router,
     render: h => h(App),
     data: {
      // 空的实例放到根组件下,所有的子组件都能调用
      Bus: new Vue()
     }
    })

    组件1触发:

    <div @click="eve"></div>
    methods: {
        eve() {
            this.$root.Bus.$emit('change','hehe'); 
        }
    }

    组件2接收:

    created() {
        this.$root.Bus.$on('change', (msg) => { //接收事件
            this.msg = msg;
        });
    }

    注:官方推荐的eventbus 解决方案的缺陷在于, 在数据传递过程中,两个组件必须都已经被渲染过。

     9.IE9报vuex requires a Promise polyfill in this browser问题解决

    因为使用了 ES6 中用来传递异步消息的的Promise,而IE低版本的浏览器不支持。

    解决方法
    第一步: 安装 babel-polyfill 

    babel-polyfill可以模拟ES6使用的环境,可以使用ES6的所有新方法

    npm install --save-dev babel-polyfill

    第二步: 在 Webpack/Browserify/Node中使用

    在webpack.config.js文件中把

    module.exports = {
        entry: {
            app: './src/main.js'
        }
    }

    替换为:

    module.exports = {
        entry: {
            app: ["babel-polyfill", "./src/main.js"]
        }
    };

    当然还有其它两种引入方式:

    • require("babel-polyfill");
    • import "babel-polyfill";

    10.启动Vue项目时提示: [BABEL] ... max of "500KB".

    在项目的根目录下找到 .babelrc 文件,增加 "compact": false ,如:

    {
      "compact": false,
      "presets": ["env", "react", "stage-0"],
      "plugins": [
        "transform-runtime"
      ]
    }

    如果不存在则手动创建该文件,并填写内容如:

    {
      "compact": false
    }

     11.在main.js中监听微信浏览器返回按钮,让其不能返回

    if(from.name == 'staffInfo' && to.name == 'Login'){
        next({path:'/staffInfo',query:{redirect:from.fullPath}});
    }else if(from.name == 'acountFill' && to.name == 'Login'){
        next({path:'/acount/acountFill',query:{redirect:from.fullPath}});
    }

    12.pdf.js默认不显示电子签章(数字签名)问题解决

    1. pdfjs 旧版本
    pdf.worker.js 找到

    if(this.data.fieldType === 'Sig') {
        warn('unimplemented annotation type: Widget signature');
        return false;
    }

    注解上面代码.
    2. pdfjs 新 版本v1.10.88
    pdf.worker.js 找到

    if(data.fieldType === 'Sig') {
        _this2.setFlags(_util.AnnotationFlag.HIDDEN);
    } 

    13.pdf.js预览,中文显示乱码解决方法

    有可能是有pdf不支持的字体格式,引入pdf.js的字体试试

    const CMAP_URL = 'https://unpkg.com/pdfjs-dist@2.0.489/cmaps/';
    pdfjsLib.getDocument({
        data: pdfData,
        cMapUrl: CMAP_URL,
        cMapPacked: true,
    })

    14.解决Vue引入百度地图JSSDK:BMap is undefined 问题

    export default {
      init: function (){
        //console.log("初始化百度地图脚本...");
        const AK = "AK密钥";
        const BMap_URL = "https://api.map.baidu.com/api?v=2.0&ak="+ AK +"&s=1&callback=onBMapCallback";
        return new Promise((resolve, reject) => {
          // 如果已加载直接返回
          if(typeof BMap !== "undefined") {
            resolve(BMap);
            return true;
          }
          // 百度地图异步加载回调处理
          window.onBMapCallback = function () {
            console.log("百度地图脚本初始化成功...");
            resolve(BMap);
          };
    
          // 插入script脚本
          let scriptNode = document.createElement("script");
          scriptNode.setAttribute("type", "text/javascript");
          scriptNode.setAttribute("src", BMap_URL);
          document.body.appendChild(scriptNode);
        });
      }
    } 

    说明:

    • 直接使用官网提供的引用地址:http://api.map.baidu.com/api?v=2.0&ak=您的密钥
    • 启用 callback 参数,异步加载必须使用此参数才可以生效
    • 启用 https 配置,通过 s=1 参数实现
    • API版本为2.0,经测试使用,发现3.0版本在HTTPS环境下是有问题的,脚本内部某些请求固定使用HTTP,无法正常使用。

    参考地址:https://segmentfault.com/a/1190000012815739

    15.本地启动vue项目,host配置域名访问出现Invalid Host header 服务器域名访问出现的问题

    在webpack.dev.config.js中找到 devServer下的hot,再下面添加 disableHostCheck: true,来解决127.0.0.1指向其他域名时出现"Invalid Host header"问题

    如图所示:

    16.vue项目中在使用vue-router切换页面的时候滚动条怎样自动滚动到顶部?

    有时候我们需要页面滚动条滚动到某一固定的位置,一般使用Window scrollTo() 方法。

    语法就是:scrollTo(xpos,ypos)

    xpos:必需。要在窗口文档显示区左上角显示的文档的 x 坐标。

    ypos:必需。要在窗口文档显示区左上角显示的文档的 y 坐标。

    例如滚动内容的坐标位置100,500:

    window.scrollTo(100,500);

    好了,这个scrollTop这儿只是简单介绍一下,下面我们介绍下veu-router中的滚动行为。

    使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router 能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。

    注意: 这个功能只在 HTML5 history 模式下可用。

    当创建一个 Router 实例,你可以提供一个 scrollBehavior 方法:

    const router = new VueRouter({
      routes: [...],
      scrollBehavior (to, from, savedPosition) {
        // return 期望滚动到哪个的位置
      }
    })

    scrollBehavior 方法接收 to 和 from 路由对象。第三个参数 savedPosition 当且仅当 popstate 导航 (通过浏览器的 前进/后退 按钮触发) 时才可用。

    这个方法返回滚动位置的对象信息,长这样:

    • { x: number, y: number }
    • { selector: string, offset? : { x: number, y: number }} (offset 只在 2.6.0+ 支持)

    如果返回一个 falsy (译者注:falsy 不是 false参考这里)的值,或者是一个空对象,那么不会发生滚动。

    举例:

    scrollBehavior (to, from, savedPosition) {
      return { x: 0, y: 0 }
    }

    对于所有路由导航,简单地让页面滚动到顶部。

    返回 savedPosition,在按下 后退/前进 按钮时,就会像浏览器的原生表现那样

    scrollBehavior (to, from, savedPosition) {
      if (savedPosition) {
        return savedPosition
      } else {
        return { x: 0, y: 0 }
      }
    }

    如果你要模拟『滚动到锚点』的行为:

    scrollBehavior (to, from, savedPosition) {
      if (to.hash) {
        return {
          selector: to.hash
        }
      }
    }

    我们还可以利用路由元信息更细颗粒度地控制滚动。

     routes: [
        { path: '/', component: Home, meta: { scrollToTop: true }},
        { path: '/foo', component: Foo },
        { path: '/bar', component: Bar, meta: { scrollToTop: true }}
      ]

    完整的例子:

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    
    Vue.use(VueRouter)
    
    const Home = { template: '<div>home</div>' }
    const Foo = { template: '<div>foo</div>' }
    const Bar = {
      template: `
        <div>
          bar
          <div style="height:500px"></div>
          <p id="anchor">Anchor</p>
        </div>
      `
    }
    
    // scrollBehavior:
    // - only available in html5 history mode
    // - defaults to no scroll behavior
    // - return false to prevent scroll
    const scrollBehavior = (to, from, savedPosition) => {
      if (savedPosition) {
        // savedPosition is only available for popstate navigations.
        return savedPosition
      } else {
        const position = {}
        // new navigation.
        // scroll to anchor by returning the selector
        if (to.hash) {
          position.selector = to.hash
        }
        // check if any matched route config has meta that requires scrolling to top
        if (to.matched.some(m => m.meta.scrollToTop)) {
          // cords will be used if no selector is provided,
          // or if the selector didn't match any element.
          position.x = 0
          position.y = 0
        }
        // if the returned position is falsy or an empty object,
        // will retain current scroll position.
        return position
      }
    }
    
    const router = new VueRouter({
      mode: 'history',
      base: __dirname,
      scrollBehavior,
      routes: [
        { path: '/', component: Home, meta: { scrollToTop: true }},
        { path: '/foo', component: Foo },
        { path: '/bar', component: Bar, meta: { scrollToTop: true }}
      ]
    })
    
    new Vue({
      router,
      template: `
        <div id="app">
          <h1>Scroll Behavior</h1>
          <ul>
            <li><router-link to="/">/</router-link></li>
            <li><router-link to="/foo">/foo</router-link></li>
            <li><router-link to="/bar">/bar</router-link></li>
            <li><router-link to="/bar#anchor">/bar#anchor</router-link></li>
          </ul>
          <router-view class="view"></router-view>
        </div>
      `
    }).$mount('#app')

    在网上查了一下,网友说还可以试试在main.js入口文件配合vue-router写这个

    router.afterEach((to,from,next) => {
        window.scrollTo(0,0);
    });

     17.tips:webpack中alias配置中的“@”的作用

    如题所示,build文件夹下的webpack.base.conf.js

    resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
          'vue$': 'vue/dist/vue.esm.js',
          '@': resolve('src')
        }
      }

    其中的@的意思是:只是一个别名而已。这里设置别名是为了让后续引用的地方减少路径的复杂度。

    //例如
    src
    - components
      - a.vue
    - router
      - home
        - index.vue
    
    index.vue 里,正常引用 A 组件:
    import A from '../../components/a.vue'
    如果设置了 alias 后。
    alias: {
     'vue$': 'vue/dist/vue.esm.js',
     '@': resolve('src')
    }
    
    引用的地方路径就可以这样了
    import A from '@/components/a.vue'
    这里的 @ 就起到了【resolve('src')】路径的作用。

     18.tips:package.json中的dependencies与devDependencies之间的区别

    –save-dev 和 –save 的区别

    我们在使用npm install 安装模块或插件的时候,有两种命令把他们写入到 package.json 文件里面去,比如:

    • –save-dev 安装的 插件,被写入到 devDependencies 对象里面去

    • –save 安装的 插件 ,被写入到 dependencies 对象里面去

    devDependencies 是只会在开发环境下依赖的模块,生产环境不会被打入包内。

    dependencies 是不仅在开发环境使用,在生成环境也需要。

     19.tips:package.json设置环境变量

    三种方法可以在package.json设置环境变量。

    先安装cross-env:

    npm install --save-dev cross-env

    package.json设置:

    {
      "scripts": {
        "dev1": "export WEBPACK_ENV=production && npx webpack -p",  ## mac
        "dev1": "set WEBPACK_ENV=production && npx webpack -p", ## windows
        "dev2": "cross-env CURRENT_ENV=development webpack-dev-server --inline --progress", ## 兼容所有平台
      }
    }

    设置环境变量的作用:

    在项目的js脚本中,通过process.env这个对象就可以访问到设置的环境变量结合打包软件webpack等等,实现不同的代码逻辑:

    console.log(process.env.WEBPACK_ENV)
    console.log(process.env.CURRENT_ENV)

     扩展参考:阮一峰:npm scripts 使用指南

  • 相关阅读:
    北京爱丽丝幻橙科技有限公司
    红杉资本中国基金:创业者背后的创业者
    关于我们_ | 腕表时代watchtimes.com.cn
    当你想放弃的时候,问一下自己你尽力了吗
    李圣杰_百度百科
    范思哲
    DOM Traversal Example | Documentation | Qt Project
    关于QT中evaluateJavaScript()函数返回值的处理问题
    JS获取整个HTML网页代码
    javascript
  • 原文地址:https://www.cnblogs.com/moqiutao/p/8017340.html
Copyright © 2011-2022 走看看