在工作中用到的 vue

2019/07/11 vue

罗列出工作中用到一些 vue 知识点

有些是新特性,有些事不常用,但是可以很好的解决工作中问题的知识点

require.context

这个应该是webpack里面的特性,但是文档里面提到了,那就拿出来说一说。Vue cli3 + 可以使用 require.context 只全局注册这些非常通用的基础组件

prop

这个说法有点不准确,又好像是准确的,因为在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或者对象类型的 prop 来说

在子组件改变这个对象或者数组本身将会影响到父组件的状态。这个时候我们可以用深层拷贝解决这个问题(JSON.parse(JSON.stringify(xxx))这个方法有弊端,或者使用其他方式深层拷贝)

prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用,进行数据的各项操作。在这种情况下,最好定义一个本地的 data 属性并将这个 prop 用作其初始值:

.sync 实现父子组件的双向数据流

这个是文档给出实现双向数据流的方法,有时候特别管用,我有一次在用 v-if 切换子组件的时候,数据没有方法完全清空,就只能使用她了。 有可能是因为如图的原因,反正我是使用她解决的。

父子组件之间传递是单向的,但有时候我们需要双向数据流,这时候就需要使用.sync 修饰符,.sync 不能配合表达式一起用

父组件

<text-document v-bind:title.sync="doc.title"></text-document>

子组件

this.$emit('update:title', newTitle)

Provide 给所有的后代组件提供数据和方法

在官网中是这样说的:

provide 选项允许我们指定我们想要提供给后代组件的数据/方法。在这个例子中,就是 <google-map> 内部的 getMap 方法:
provide: function () {
  return {
    getMap: this.getMap
  }
}
然后在任何后代组件里,我们都可以使用 inject 选项来接收指定的我们想要添加在这个实例上的属性:
inject: ['getMap']

好像在react里面常常用到类似的特性

//父组件:
provide: { //provide 是一个对象,提供一个属性或方法
  foo: '这是 foo',
  fooMethod:()=>{
    console.log('父组件 fooMethod 被调用')
  }
},

// 子或者孙子组件
inject: ['foo','fooMethod'], //数组或者对象,注入到子组件
mounted() {
  this.fooMethod()
  console.log(this.foo)
}
//在父组件下面所有的子组件都可以利用inject
provide 和 inject 绑定并不是可响应的。这是官方刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的,对象是因为是引用类型


//父组件:
provide: { 
  foo: '这是 foo'
},
mounted(){
  this.foo='这是新的 foo'
}

// 子或者孙子组件
inject: ['foo'], 
mounted() {
  console.log(this.foo) //子组件打印的还是'这是 foo'

v-show 使用的一种场景

v-showv-if 的主要区别在是否真正的渲染,来回频繁切换的性能对比。在大多数情况下我使用的是 v-if ,用户切换的不频繁。但是有一次在用户切换不频繁的情况下我使用了v-show。原因是一个移动端项目,用户点击一个按钮的时候,出现一个弹窗,默认要弹起软键盘。我通过 focus() 弹起键盘。因为是父子组件的关系,总是会出现第一次渲染弹起键盘不成功,在focus() 事件被触发的时候,有可能子组件还没有渲染完。所以我才用了 v-show ,在首次加载页面的时候渲染,然后就不会出现,父组件通过 refs 调用子组件的事件失败了。

在写这篇文章的时候想到了另一个解决方案,是当时没有想到的。就是在子组件 mounted 的时候调用 focus() ,而不是通过父组件调用。因为需求是字组件一出现,就弹起软键盘。

记录工作中遇到过的问题,或者踩过的坑,或者和同事去交流的时候,恍然间会发现,其实还有更好的思路,和实现方式,只是自己当时写的时候,陷入了自己原来思路的死胡同。所以我以后要经常写,要多写,在写的时候,就发现原来还有更好的方式

Vue 中对象新增属性不能响应的问题

这个问题,我是一直都知道了,可是再一次项目中,傻逼的我居然忘记了。还找了半天问题,问了同事,想了很久之后才明白。或许是我从骨子里面没有真正的理解吧。

事情经过: 以前项目中我喜欢在 data 里面初始化数据,如果是对象,会给对象初始化属性名,给默认属性值。在最近的一次项目我看项目里面都只有初始化一个空对象,我就随项目走了。然后就踩坑了,忘记vue 不能给对象新增属性添加响应问题了。看了半天都不知为啥数据没有响应式变化,蠢到家了,vm.$set() 添加属性可以响应式变化,其实还可以通过 es6 的对象解构去实现 this.obj = {...this.obj}

$attrs

$attrs 场景:如果父传子有很多值,那么在子组件需要定义多个 props 解决:$attrs 获取子传父中未在 props 定义的值

// 父组件
<home title="这是标题" width="80" height="80" imgUrl="imgUrl"/>
// 子组件
mounted() {
  console.log(this.$attrs) //{title: "这是标题", width: "80", height: "80", imgUrl: "imgUrl"}
},

相对应的如果子组件定义了 props,打印的值就是剔除定义的属性

props: {
  width: {
    type: String,
    default: ''
  }
},
mounted() {
  console.log(this.$attrs) //{title: "这是标题", height: "80", imgUrl: "imgUrl"}
},

使用 this.$attrs 父组件带过来的数据的时候要定义后在使用,否则可能会有警告信错误

问题

创建和编辑页面用到同一个 component 组件的时候,默认组件不会在触发 vue 里面的 createmounted 钩子函数?(因为 vue 默认是高度复用)

解决方案一 : 可以在 router-view 组件上面加一个唯一的 key 来处理,保证唯一的 key ,路由切换的时候就会重新触发渲染钩子

<router-view :key="key"></router-view>

computed: {
  key() {
    // 只要保证 key 唯一性就可以了,保证不同页面的 key 不相同
    return this.$route.fullPath
  }
 }

解决方法二:在当前页面使用 watch 监听路由是否发生变化

watch:{
  '$route'(newVal,oldVal){ //路由发生了编辑
    if (newVal.path == "/systemSetting/appdetails") {
    //进行数据的初始化
  }
}
},

解决方法三:使用 v-if 强制所有组件重新渲染,可以使用 provide 进行依赖注册

<router-view v-if="isRouterAlive"></router-view>

  methods: {
    reload () {
      this.isRouterAlive = false
      this.$nextTick(() => {
        this.isRouterAlive = true
      })
    },
   }

解决方案都是根据路由的变化,对组件进行重新渲染或者初始化

页面加载时需要让文本框获取焦点

用法:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM

mounted(){ //因为 mounted 阶段 dom 并未渲染完毕,所以需要$nextTick
  this.$nextTick(() => {
    this.$refs.inputs.focus() //通过 $refs 获取dom 并绑定 focus 方法
  })
}

一名伪程序猿——sunseekers,曾被bug虐的体无完肤,却依旧待他如初恋。

如果我改过的某一个bug,吐槽过的某一个需求,写过的某一行代码

曾在你的心里荡起涟漪,那至少说明在逝去的岁月里,我们在某一刻,共同经历着一样的情愫。

有时候,虽然素未谋面。却已相识很久,很微妙也很知足。


如果你喜欢我写过的某一个文字,请支持我,鼓励我,你的鼓励是我最大的动力来源

当然恰好你也喜欢我的话,我们可以互相关注,相互学习的哟!

sunseekers

Search

    Table of Contents