使用Vue3开发TodoMVC


最近在学习Vue3.0的一些新特性,就想着使用Vue3来编写一个todoMVC的示例。本示例是模仿官网的TodoMVC,但是本示例中所有代码都是使用了Vue3的语法。
功能上基本上实现了,不过官方的示例上使用了Local Storage本地缓存来缓存数据,我在本示例中没有使用。另外ui样式我没有完全还原,也算是偷下懒吧。

官网示例:https://cn.vuejs.org/v2/examples/todomvc.html

先来看一下效果

开发中的几个问题

主要用到Vue3的conposition API有:ref, reactive, computed, watchEffect, watch, toRefs, nextTick,
功能我就不细讲了,后面会附上完整代码,主要讲几点在开发过程中遇到的问题,也是Vue3中的一些小改动的问题。

1.列表item的input输入框自动获取焦点

在官网示例中是使用了自定义指令去完成的,先自己定义一个自定义指令,之后再在input标签中去使用


directives: {
 "todo-focus": function(el, binding) {
    if (binding.value) {
      el.focus();
    }
  }
}

而我在本例中想使用ref来获取dom元素,从而触发input的onfocus事件。
我们知道在Vue2.x中可以使用this.$refs.xxx来获取到对应的dom元素,可是Vue3.0中是没办法使用这种方法去获取的。

查阅了Vue3.0官方文档之后,发现Vue3对ref的使用做了修改。

  • Vue2:
  • Vue3:



2. 在v-for中获取ref

而对在v-for中使用ref,Vue3不再在 $ref 中自动创建数组,而是需要用一个函数来绑定。(参考文档:https://composition-api.vuejs.org/zh/api.html#模板-refs)

  
//Vue2
export default {
  data() {
    return {
      itemRefs: []
    }
  },
  methods: {
    setItemRef(el) {
      this.itemRefs.push(el)
    }
  }
}

//Vue3
import { ref } from 'vue'

export default {
  setup() {
    let itemRefs = []
    const setItemRef = el => {
      itemRefs.push(el)
    }
    onBeforeUpdate(() => {
      itemRefs = []
    })
    onUpdated(() => {
      console.log(itemRefs)
    })
    return {
      itemRefs,
      setItemRef
    }
  }
}

在本例中使用了另一种写法,也是一样。


setup() {
  const editRefList = ref([]);
  watchEffect(async () => {
    if (state.itemInputValue) {
      await nextTick();
      editRefList.value[state.currentTodoId].focus();
    }
  });
  return {editRefList}
}

3. nextTick的使用

在Vue2中我们会这样使用nextTick

this.$nextTick(()=> {
  //获取更新后的DOM
})

而在Vue3中这样使用

import { createApp, nextTick } from 'vue'
const app = createApp({
  setup() {
    const message = ref('Hello!')
    const changeMessage = async newMessage => {
      message.value = newMessage
      // 这里获取DOM的value是旧值
      await nextTick()
      // nextTick 后获取DOM的value是更新后的值
      console.log('Now DOM is updated')
    }
  }
})

4. watchEffect 和 watch

(1)watchEffect

vue3中新增了watchEffect的方法,也是可以用来监听数据。watchEffect() 会立即执行传入的函数,并响应式侦听其依赖,并在其依赖变更时重新运行该函数。

  • 基本用法
const count = ref(0)

// 初次直接执行,打印出 0
watchEffect(() => console.log(count.value))

setTimeout(() => {
  // 被侦听的数据发生变化,触发函数打印出 1
  count.value++
}, 1000)
  • 停止侦听

watchEffect() 使用时返回一个函数,当执行这个返回的函数时,就停止侦听。

const stop = watchEffect(() => {
  /* ... */
})

// 停止侦听
stop()
(2)watch

watch的写法与vue2稍稍有点不同

  • watch 侦听单个数据源

侦听的数据可以是个 reactive 创建出的响应式数据(拥有返回值的 getter 函数),也可以是个 ref

watch接收三个参数:
参数1:监听的数据源,可以是一个ref获取是一个函数
参数2:回调函数(val, oldVal)=> {}
参数3:额外的配置 是一个是对象时进行深度监听,添加 { deep:true, immediate: true}
// 侦听一个 getter
const state = reactive({ count: 0 })
watch(
  () => state.count,
  (count, prevCount) => {
    /* ... */
  },
  { deep:true, immediate: true}
)

// 直接侦听一个 ref
const count = ref(0)
watch(count, (count, prevCount) => {
  /* ... */
})
  • watch 侦听多个数据源

在侦听多个数据源时,把参数以数组的形式给 watch

watch([ref1, ref2], ([newRef1, newRef2],   [prevRef1, prevRef2]) => {
  /* ... */
})

最后

本例也是自己刚接触vue3之后写的,可能写的并不是很好,如果有哪里有错误或者可优化的请多多指导。

完整代码





vue