vue学习记录: 遇到过的问题记录

书写规范

  • prop 必须指定 type
{
    // ...
    props: {
      title: String,
      likes: Number,
      isPublished: Boolean,
      commentIds: Array,
      author: Object
    }
    //...
}

对于须要默认值的prop,建议指定其默认值javascript

项目构建

  • vue-cli 安装中找不到vue命令

这是在ubuntu系统中遇到的,全局安装后能够css

npm install -g  vue-cli

图片描述

Vue 组件间通讯

  • 父子 props/event $parent/$children ref provide/inject
  • 兄弟 bus vuex
  • 跨级 bus vuex provide.inject
跨层级的组件间通信可使用 eventbus
可是要注意两点:
event 会注册到全局,要注意模块化
注意销毁,否则会使用两次
一、在vue中子组件为什么不能够修改父组件传递的Prop, 若是修改了,二、Vue是如何监控到属性的修改并给出警告的
  • 单向数据流,易于监测数据的流动,出现了错误能够更加迅速的定位到错误发生位置

每当父组件属性值修改时, 该值都将被覆盖。
——> 引伸出一个问题:html

若是在子组件须要修改prop呢?
- 经过事件修改父组件状态
- 或者子组件把prop赋给data()或者comuted,
  • 若是修改了:

Vue 是如何监控到属性的修改并给出警告的前端

单向数据流

封装Vue组件的一些技巧
vue 最先是双向数据流,子组件能够改变 props ,以后由于引起不少问题而改为单向数据流。如今在子组件内触发修改会致使报错。
以函数透传的形式实现控制子组件修改父组件状态不是一个好办法。vue

传统实现仍是 v-modeljava

可是,v-model 里子组件不能直接改变父组件状态,而是要经过事件,本质上依然是单向数据流。react

webpack

https://vuejs-templates.githu...webpack

打包优化

优化vue项目打包速度(webpack)ios

懒加载(按需加载路由)

webpack 中提供了 require.ensure()来实现按需加载。之前引入路由是经过 import 这样的方式引入,改成 const 定义的方式进行引入。git

  • 不进行页面按需加载引入方式:
import  home   from '../../common/home.vue'
  • 进行页面按需加载的引入方式:
const  home = r => require.ensure( [], () => r (require('../../common/home.vue')))

https://blog.csdn.net/qq_2762...

slot

slot 在ui库中有普遍的应用

  • <slot></slot>标签,简单来讲就是占位符,它会帮你占好位置,等你须要的时候直接将html传入,它会帮你显示出来。
  • 也有人说:props能够将数据从父组件传入子组件,slot能够将html从父组件传入子组件。那么如何实现呢?

单个插槽:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <script type="text/javascript" src="vue.min.js"></script>
    </head>
    <body>
        <div id="app">
            <h1>我是父组件的标题</h1>
            <my-component>
                <p>这是一些初始内容</p>
                <p>这是更多的初始内容</p>
            </my-component>
        </div>
        <script type="text/javascript">
            Vue.component('my-component', {
              // 有效,由于是在正确的做用域内
              template: '<div>\
                            <h2>我是子组件的标题</h2>\
                            <slot>只有在没有要分发的内容时才会显示。</slot>\
                        </div>',
              data: function () {
                return {
                  
                }
              }
            });
            new Vue({
                el:'#app',
                data:{
                    msg:'你好啊'
                }
            })

        </script>
    </body>
</html>

组件中的模板中写入slot标签,在父级调用子组件的时候传入html便可。

具名插槽

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <script type="text/javascript" src="vue.min.js"></script>
    </head>
    <body>
        <div id="app">
            <my-component>
                  <h1 slot="header">这里多是一个页面标题</h1>

                  <p>主要内容的一个段落。</p>
                  <p>另外一个主要段落。</p>

                  <p slot="footer">这里有一些联系信息</p>
            </my-component>
        </div>
        <script type="text/javascript">
            Vue.component('my-component', {
              // 有效,由于是在正确的做用域内
              template: '<div class="container">\
                          <header>\
                            <slot name="header"></slot>\
                          </header>\
                           <main>\
                            <slot></slot>\
                          </main>\
                          <footer>\
                            <slot name="footer"></slot>\
                          </footer>\
                        </div>',
              data: function () {
                return {
                  
                }
              }
            });
            new Vue({
                el:'#app',
                data:{
                    msg:'你好啊'
                }
            })

        </script>
    </body>
</html>

具名插槽,顾名思义当有多个slot标签时,你须要给他们起个本身的名字,在父组件调用时须要slot="内部的对应名字",当存在没有命名的slot标签时,父级组件传入的默认html代码将所有输出在无名的slot标签中。

做用域插槽

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <script type="text/javascript" src="vue.min.js"></script>
    </head>
    <body>
        <div id="app">
             <!-- 在父级中,具备特殊特性 slot-scope 的 <template> 元素必须存在,表示它是做用域插槽的模板。slot-scope 的值将被用做一个临时变量名,此变量接收从子组件传递过来的 prop 对象: -->
             <child>
                <template scope="props">
                  <span>hello from parent</span><br>
                  <span>{{ props.text }}</span>
                </template>
            </child>
        </div>
        <script type="text/javascript">
            // 在子组件中,只需将数据传递到插槽,就像你将 prop 传递给组件同样:
            Vue.component('child',{
               template:'<ul>' +
                            '<slot text="hello from child"></slot>' +
                         '</ul>',
                data:function(){
                  return {

                  }
                },
            });
            new Vue({
                el:'#app',
                data:{
                    msg:'你好啊'
                }
            })

        </script>
    </body>
</html>

https://codepen.io/AlexZ33/pe...

做用域插槽是一种特殊类型的插槽,用做一个 (能被传递数据的) 可重用模板,来代替已经渲染好的元素。
其实就是至关于,在父组件中能够获取到子组件传递出来的props对象,从而渲染到父组件上。

watch

Vue开发——watch监听数组、对象、变量
这里要注意的是对数组的watch

clipboard.png
vue——数组的深度监听

组件 v-if 和 v-show 切换时生命周期钩子的执行

v-if
初始渲染
初始值为 false 组件不会渲染,生命周期钩子不会执行,v-if 的渲染是惰性的。
初始值为 true 时,组件会进行渲染,并依次执行 beforeCreate,created,beforeMount,mounted 钩子。
切换
false => true
依次执行 beforeCreate,created,beforeMount,mounted 钩子。
true => false
依次执行 beforeDestroy,destroyed 钩子。
v-show
渲染
不管初始状态,组件都会渲染,依次执行 beforeCreate,created,beforeMount,mounted 钩子,v-show 的渲染是非惰性的。
切换
对生命周期钩子无影响,切换时组件始终保持在 mounted 钩子。

指令

v-cloak

vue v-cloak 解决页面加载时闪烁出现vue标签或者指令的问题

自定义指令

v-WaterMark

// chart/WaterMark.js
export default class WaterMark {
  constructor (userNm, userCd) {
    this.userNm = userNm
    this.userCd = userCd
  }
  draw () {
    let canvas = document.createElement('canvas')
    let ctx = canvas.getContext('2d')
    canvas.width = 250
    canvas.height = 130
    ctx.translate(canvas.width / 2, canvas.height / 2 - 35)
    ctx.rotate(-Math.PI / 12)
    ctx.font = '700 12px/Mircosoft Yahei'
    ctx.textAlign = 'center'
    ctx.textBaseline = 'middle'
    ctx.fillStyle = '#eaf0f5'
    // ctx.fillStyle = '#f00'
    ctx.fillText(`镜心的小树屋 ${this.userNm} ${this.userCd}`, 0, 0)
    return canvas.toDataURL('image/png')
  }
}
// rule.js
/**
 * 用户信息相关
 */
exports.useInfor = {
  data: {
    name: '',
    userCd: '',
    userNm: ''
  },
  clear: function () {
    this.data = {
      name: '',
      userCd: '',
      userNm: '',
      flag: false
    }
  }
}
// directives/WaterMark.js
import WaterMark from '../chart/WaterMark.js'
import { useInfor } from '../rule'

export default {
  inserted (el, binding) {
    let timer = setInterval(() => {
      if (useInfor.data.userNm && useInfor.data.userCd) {
        let wMark = new WaterMark(useInfor.data.userNm, useInfor.data.userCd)
        let imageSrc = wMark.draw()
        if (binding.value && binding.value === false) return
        el.style.background = `#fff url(${imageSrc}) repeat top left`
        clearInterval(timer)
      }
    }, 50)
  }
}

clipboard.png

v-check

v-focus

// https://cn.vuejs.org/v2/guide/custom-directive.html#%E9%92%A9%E5%AD%90%E5%87%BD%E6%95%B0
// 注册一个全局自定义指令 'v-focus'
export default {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }
}

路由之间跳转

  • 声明式(标签跳转)
  • 编程式( js 跳转) router.push('index')

clipboard.png

页面刷新

最近遇到一个需求,须要刷新当前页面来更新数据
vue 无痕刷新

组件局部刷新

【BUG】iview多选框插件默认选中有问题,局部刷新后会取消选中状态?

clipboard.png

clipboard.png

clipboard.png

clipboard.png

clipboard.png

[Vue warn]: Invalid prop: type check failed for prop "value". Expected String, Number, got Undefined. Vue出现该错误的解决办法

https://www.cnblogs.com/sifo/...

iview样式修改不生效

在使用vue框架iview是常常须要在组件里面修改某一个样式,为了防止组件之间的样式污染,咱们须要使用scoped来限制在当前组件内生效,但每每样式会没法生效。我以前的解决方案是在当前这个组件的父级加一个只有当前组件才有的class而后早style没有scoped中去写样式,这样既能够改变iview自带的样式,也能够人为去限制组件之间的样式污染,这也是当时没有办法下本身想到的惟一的办法。最近又发现一个新的解决方案/deep/深度选择器 ->戳这里

clipboard.png

.reset-sub-modal /deep/ .ivu-modal-footer
    padding-bottom: 25px

clipboard.png

生命周期

图片描述

https://www.cnblogs.com/golov...

vue中的dom异步更新及$nextTick()

clipboard.png

一、dom异步更新的原理

观察到数据变化,vue开启一个队列,并缓冲同一事件循环的全部数据变化;
若是同一个watcher被屡次触发,只会被推入队列中一次;(去重,避免没必要要计算和DOM操做)
在下一个事件循环tick中,vue刷新队列并执行已去重的工做;

二、vue.nextTick()

所以,改数据(eg vm.someData = ’88’)时,组件不会立刻更新,而是在vue下一个tick刷新队列时更新;
为了在数据变化后,要在vue的dom状态更新后作什么,可在数据变化后调用vue.nextTick(callback),则dom更新完成后会调用回调函数;

三、nextTick的使用场景

Vue生命周期的created()钩子函数进行的DOM操做必定要放在Vue.nextTick()的回调函数中;
在数据变化后要执行的某个操做,而这个操做须要使用随数据改变而改变的DOM结构的时候,这个操做都应该放进Vue.nextTick()的回调函数中;

更多原理和示例戳这里

内置组件component

文档
简单示例: https://jsfiddle.net/chrisvfr...

正常项目中:

clipboard.png

clipboard.png

clipboard.png

clipboard.png

.sync

对于VUE的初学者来说,确定会感受prop的写法很麻烦,很讨厌!你确定想若是prop也能够实现双向绑定那怎是一个爽字了得!不过现实是残酷的,若是子组件能够任意修改父组件的内容,那势必会带来数据的混乱,从而形成维护的困扰!毕竟父组件也是有尊严的!

https://www.jianshu.com/p/d42...

触发其余组件方法

使用 Vue.js 怎么调用其余组件的方法
中央事件总线eventbus

clipboard.png

/**
 * 中央事件总线
 * 这个插件能够在能够在全部的组件之间随意使用 
 * 经常使用于兄弟组件间通讯
 * 注意:
 * $bus.on应该在 created钩子内使用,若是在mounted使用,它可能接受不到其余组件来自created钩子发出的事件       
 * 第二点是使用了$bus.on,在beforeDestroy钩子里应该使用$bus.off解除,由于组件销毁后,就不必把监听的句柄储存在vue-bus里了
 * @param {*} Vue 传入的Vue class
 */
const install = function (Vue) {
  const Bus = new Vue ({
    methods: {
      emit (event, ...args) {
        this.$emit(event, ...args)
      },
      on (event, callback) {
        this.$on(event, callback)            
      },
      off (event, callback) {
        this.$off(event, callback)
      }
    }
  })
  Vue.prototype.$bus = Bus
}

export default install

屡次触发问题-> issue

经常使用组件

资料集合
multiselect
在 vue-multiselect 基础上建立 ImageSelect 组件
https://github.com/vuejs/awes...

组件封装

封装Vue组件的一些技巧

webpack打包速度优化

个人知乎专栏

实现label-required

clipboard.png

.label-required
    display: inline-block
    height: 33px
    line-height: 28px
    &:before
      content: '*'
      display: inline-block
      margin-right: 4px
      line-height: 1
      font-family: SimSun
      font-size: 12px
      color: #ed3f14

$parent

$parent 也能够用来访问父组件的数据。

并且子组件能够经过$parent 来直接修改父组件的数据,不会报错!

可使用props的时候,尽可能使用props显式地传递数据(能够很清楚很快速地看出子组件引用了父组件的哪些数据)。

另外在一方面,直接在子组件中修改父组件的数据是很糟糕的作法,props单向数据流就没有这种顾虑了。

禁止直接更改组件上的class样式 ,用自定义class覆盖

clipboard.png

clipboard.png

clipboard.png

自动化部署

非大厂隔离环境的话可用ssh( 大厂生产环境是隔离的 要经过跳板机 代码不可能经过ssh直接发到生产的):
Vue-CLI 3.x 自动部署项目至服务器

常见问题

组件中 data 为何是函数

为何组件中的 data 必须是一个函数,而后 return 一个对象,而 new Vue 实例里,data 能够直接是一个对象?

由于组件是用来复用的,JS 里对象是引用关系,这样做用域没有隔离;而 new Vue 的实例,是不会被复用的,所以不存在引用对象的问题。

v-model原理解析

从最初学习Vue就知道v-model能够实现双数据绑定,但它能实现绑定的原理究竟是什么呢?经过查看官方文档和各类博客资料,如下是个人理解。

根据官方文档介绍,v-model本质上就是语法糖,即利用v-model绑定数据后,其实就是既绑定了数据,又添加了一个input事件监听,以下:
https://www.cnblogs.com/attac...

双向绑定原理

这个问题几乎是面试必问的,回答也是有深有浅。基本上要知道核心的 API 是经过 Object.defineProperty() 来劫持各个属性的setter / getter,在数据变更时发布消息给订阅者,触发相应的监听回调,这也是为何 Vue.js 2.x 不支持 IE8 的缘由(IE 8 不支持此 API,且没法经过 polyfill 实现)
https://cn.vuejs.org/v2/guide...

vue.js 是采用数据劫持结合发布者-订阅者模式的方式,经过 Object.defineProperty()来劫持各个属性的 setter,getter,在数据变更时发布消息给订阅者,触发相应的监听回调。

具体步骤:
第一步:须要 observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter 和 getter 这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化

第二步:compile 解析模板指令,将模板中的变量替换成数据,而后初始化渲染页面视图,并将每一个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变更,收到通知,更新视图

第三步:Watcher 订阅者是 Observer 和 Compile 之间通讯的桥梁,主要作的事情是:

  • 在自身实例化时往属性订阅器(dep)里面添加本身
  • 自身必须有一个 update()方法
  • 待属性变更 dep.notice()通知时,能调用自身的 update() 方法,并触发 Compile 中绑定的回调,则功成身退。

第四步:MVVM 做为数据绑定的入口,整合 Observer、Compile 和 Watcher 三者,经过 Observer 来监听本身的 model 数据变化,经过 Compile 来解析编译模板指令,最终利用 Watcher 搭起 Observer 和 Compile 之间的通讯桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据 model 变动的双向绑定效果。

vue组件中各方法执行顺序是怎么样的

vue组件中各方法执行顺序是怎么样的

Props -》 Methods -》 Data -》Computed -》 Watch

clipboard.png

clipboard.png

长列表性能优化

咱们应该都知道vue会经过object.defineProperty对数据进行劫持,来实现视图响应数据的变化,然而有些时候咱们的组件就是纯粹的数据展现,不会有任何改变,咱们就不须要vue来劫持咱们的数据,在大量数据展现的状况下,这可以很明显的减小组件初始化的时间,那如何禁止vue劫持咱们的数据呢?能够经过object.freeze方法来冻结一个对象,一旦被冻结的对象就不再能被修改了。

export default {
  data: () => ({
    users: {}
  }),
  async created() {
    const users = await axios.get("/api/users");
    this.users = Object.freeze(users);
  }
};

另外须要说明的是,这里只是冻结了users的值,引用不会被冻结,当咱们须要reactive数据的时候,咱们能够从新给users赋值。

export default {
  data: () => ({
    users: []
  }),
  async created() {
    const users = await axios.get("/api/users");
    this.users = Object.freeze(users);
  },
  methods:{
    // 改变值不会触发视图响应
    this.users[0] = newValue
    // 改变引用依然会触发视图响应
    this.users = newArray
  }
};

vue-router

vue-router 有哪几种导航钩子?
  • 全局导航钩子
  • router.beforeEach(to, from, next),
  • router.beforeResolve(to, from, next),
  • router.afterEach(to, from ,next)
  • 组件内钩子
  • beforeRouteEnter,
  • beforeRouteUpdate,
  • beforeRouteLeave
  • 单独路由独享组件
  • beforeEnter
import NProgress from 'nprogress'
// http://ricostacruz.com/nprogress/

clipboard.png

vue 中 ajax 请求代码应该写在组件的 methods 中仍是 vuex 的 action 中?

若是请求来的数据不是要被其余组件公用,仅仅在请求的组件内使用,就不须要放入 vuex 的 state 里

若是被其余地方复用,请将请求放入 action 里,方便复用,并包装成 promise 返回

clipboard.png

组件开发

组件要考虑的三个基本内容:

  • 交互
  • 样式
  • 内容

组件须要提供修改样式的能力, 修改内容的能力,和基本的交互反馈能力。

而一个可复用的组件,须要开放控制粒度。一般来讲,控制粒度约高的组件,开发者使用起来就越方便,可是维护起来也越困难。肯定本身的组件控制开放到什么程度是重要的内容。

另外,也存在只提供基本的控制开放的组件。各我的会有其偏向性。而反馈组件的状态决定了组件是否易用。程序须要知道用户作了什么。

恰当的反馈,加上合适的控制,才能写出易用的组件。

封装组件

封装Vue组件的一些技巧

代码规范

vue 风格指南

工程实践

Vue 项目架构设计与工程化实践

参考

vue中的css做用域、vue中的scoped坑点
css loader 深度做用选择器
vue nextTick深刻理解-vue性能优化、DOM更新时机、事件循环机制
Vue.js 技术揭秘
Vue技术内幕
深度剖析:如何实现一个 Virtual DOM 算法
Vue使用中的小技巧
Vue问得最多的面试题
让vue-cli3.0 配置简单起来(vue.config.js编结)
Creating Vue.js Component Instances Programmatically
Vue项目经验
「Vue实践」武装你的前端项目
7个有用的Vue开发技巧
基于vue的进阶散点干货

相关文章
相关标签/搜索