10 个超强 Vue3 实战指南,由此突破新特性!(上)

简介: 本篇介绍 10 点如何从实战中学习突破 Vue JS 3 的新特性,细细看完,一定会有收获~

image.png

本篇介绍 10 点如何从实战中学习突破 Vue JS 3 的新特性,细细看完,一定会有收获~

主体译自:【Vue JS 3 — The Practical Guide】

更多学习资料:【https://github.com/Jerga99/vue-3-updates】


你的点赞投票是我最大的动力,关注走一波,【2021】有更多好看~!😀😀😀


初始化挂载



在 Vue2 中,我们在 main.js 通常这样进行初始化挂载:


new Vue({
  render: h => h(App),
  components: { App }
}).$mount('#app')


在 Vue3 中,调整为这样:


import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.mount('#app')


为什么发生这样的变化?原因是:如果我们在 Vue2 中创建多个 Vue 实例,那么所有应用(#app)都会共享全局相同的配置。


// 全局共享、相互影响
Vue.mixin({
  /* ... */
})
Vue.directive('...', {
  ...
})
const app1 = new Vue({ el: '#app-1' })
const app2 = new Vue({ el: '#app-2' })


显然,这并不是我们想要的。在 Vue3 中,你可以创建多个实例,且每个实例都可以拥有单独的配置。


import { createApp } from 'vue'
import App1 from './App1.vue'
import App2 from './App2.vue'
const app1 = createApp(App1)
const app2 = createApp(App2)
app1.mount('#app-1')
app2.mount('#app-2')
app1.directive('...', {
  ...
})
app2.directive('...', {
  ...
})


但是,这也并不影响我们设置共享全局配置,我们可以通过如下工厂函数方式实现:


import { createApp } from 'vue';
import App1 from './App1.vue';
import App2 from './App2.vue';
const createApp = (Instance) => {
    const App = createApp(Instance);
  App.directive('i-am-cool', {
      inserted: () => {
      console.log('I am cool!');
    },
  });
}
createIdolApp(App1).mount('#app-1');
createIdolApp(App2).mount('#app-2');


Composition API



受到 React 的启发,Vue3 引入 Composition API 和 “hook” 函数。有了它,Vue 组件的使用变得更加灵活,也变得更加强大。特别是针对大型应用,以下会给出示例。

以前在 Vue2 中我们是这样写组件的:获取数据,设置数据。


<script>
import { fetchResources } from '@/actions'
import ResourceDetail from '@/components/ResourceDetail'
import ResourceList from '@/components/ResourceList'
export default {
  components: {
    ResourceDetail,
    ResourceList,
  },
  data() {
    return {
      title: 'Your resources',
      selectedResource: null,
      resources: []
    }
  },
  async created() {
    this.resources = await fetchResources()
  },
  computed: {
    hasResources() {
      return this.resourceCount > 0
    },
    activeResource() {
      return this.selectedResource || (this.hasResources && this.resources[0]) || null
    },
    resourceCount(){
      return this.resources.length
    }
  },
  methods: {
    selectResource(resource) {
      this.selectedResource = {...resource}
    }
  }
}
</script>


完整代码在这里

如果我们使用 composition API,会是这样写:


import { ref, onMounted, computed } from 'vue'
import { fetchResources } from '@/actions'
export default function useResources() {
  const resources = ref([])
  const getResources = async () => resources.value = await fetchResources()
  onMounted(getResources);
  const resourceCount = computed(() => resources.value.length)
  const hasResources = computed(() => resourceCount.value > 0 )
  return {
    resources,
    resourceCount,
    hasResources
  }
}


这是一个非常简单的 Composition function 实现了获取 resources 数据的功能。

Composition 函数通常用 use 开头作为关键字,比如此处的 “useResources”,以此区别于普通函数。


下面针对以上代码关键点进行一一释义:


1.ref 会创建一个动态对象。如果你要从 ref 获取原始值,则需要取 “value” 属性,比如 —— resources.value


看以下示例:

var a = 7;
var b = a;
b = 10;
// a = 7
// b = 10
var a = ref(7);
var b = a;
b.value = 100;
// a = 100
// b = 100


我们将返回的 resoure 数组设置为 ref。是因为如果数组有新增项或移除项,这样做能在程序中有所表现。


一图胜万言:

image.png

2.getResources 函数用于获取数据。

3.onMounted 生命周期函数会在组件添加到 Dom 时调用。

4.computed 属性会随着它的依赖(resources or resourceCount)变化而重新计算。

5.  return 最后一步我们将返回 data/function,我们再向组件暴露 useResource hook 函数以供使用。


最终 hook-in:

<script>
import ResourceDetail from '@/components/ResourceDetail'
import ResourceList from '@/components/ResourceList'
import useResources from '@/composition/useResources';
export default {
  components: {
    ResourceDetail,
    ResourceList,
  },
  data() {
    return {
      title: 'Your resources',
      selectedResource: null
    }
  },
  setup() {
    return {
      ...useResources() // 在 setup 里
    }
  },
  computed: {
    activeResource() {
      return this.selectedResource || (this.hasResources && this.resources[0]) || null
    }
  },
  methods: {
    selectResource(resource) {
      this.selectedResource = {...resource}
    }
  }
}
</script>


我们再 setup 中进行引用,返回值都可以再通过 this 进行调用。

我们在 computed 和 methods 也能同样进行调用 Composition 函数的返回。

注意:setup 钩子函数执行在组件实例创建(created)之前。


在组件创建前 setup 中 hook 被执行,只要 props 被解析,服务就会以 composition API 作为入口。因为此时当 setup 执行时,组件实例还未生成,没有 this 对象。

神奇吗?我们就这样将获取数据进行封装然后应用到了 hook 调用中。

再写一个对 resources 资源进行搜索过滤的功能:


  • useSearchResource
import { ref, computed } from 'vue'
export default function useSearchResource(resources) {
  const searchQuery = ref('')
  const setSearchQuery = searched => {
    searchQuery.value = searched
  }
  const searchedResources = computed(() => {
    if (!searchQuery.value) {
      return resources.value
    }
    const lcSearch = searchQuery.value.toLocaleLowerCase();
    return resources.value.filter(r => {
      const title = r?.title.toLocaleLowerCase()
      return title.includes(lcSearch)
    })
  })
  return {
    setSearchQuery,
    searchedResources
  }
}


  • useResources
export default function useResources() {
  const resources = ref([])
  const getResources = async () => resources.value = await fetchResources()
  onMounted(getResources);
  const resourceCount = computed(() => resources.value.length)
  const hasResources = computed(() => resourceCount.value > 0 )
  const { searchedResources, setSearchQuery } = useSearchResources(resources)
  return {
    resources: searchedResources,
    resourceCount,
    hasResources,
    setSearchQuery
  }
}


拆解分析:

  1. searchQuery 包含一个空字符串,使用了 ref,computed searchedResources 可以检测 searchQuery 的变化值。
  2. setSearchQuery 是一个简单的赋值给 searchQuery 的函数。
  3. searchedResources会在 searchQuery 或 resources 变化的时候触发。
  4. searchedResources 负责过滤 resources。每个 resource 包含一个 title,如果 title 包含 searchedQuery 字符串,那么 resource 就会被加入到 searchedResources 数组中。
  5. 最后函数返回 setSearchQuerysearchedResourced,再在 useResources 中进行引用及返回。


再看下在组件中使用它到底有多简单:

<template>
...
<input
  @keyup="handleSearch"
  type="text"
  class="form-control"
  placeholder="Some title" />
...
</template>
<script>
...
methods: {
  ...
  handleSearch(e) {
    this.setSearchQuery(e.target.value)
  }
}
...
</script>


真有你的! 无论何时执行 setSearchQuery 更改 searchQuery 的值,都将重新执行 searchedResources 将其进行过滤操作并返回结果。

以上便是超重要的新特性 composition API 的实战介绍。


Data 选项



在 Vue2 中,data选项不是对象就函数,但是在 Vue3 中将只能是函数。这将被统一成标准。


<script>
  export default {
    data() {
      return {
        someData: '1234'
      }
    }
  }
</script>


Filters 被移除



不会再出现这样的写法:

<h1>{{title | capitalized }} </h1>


这样的表达式不是合法有效的 Javascript,在 Vue 中实现这样的写法需要额外的成本。它可以很容易被转化为计算属性或函数。


computed: {
 capitalizedTitle() {
   return title[0].toUpperCase + title.slice(1);
  }
}


多个根标签



在 Vue2 中我们经常这样包裹我们的根标签:


<template>
  <div>
    <h1>...</h1>
    <div class="container">...</div>
    ...
  </div>
</template>


在 Vue3 中将不再有此限制:


<template>
  <h1>...</h1>
  <div class="container">...</div>
  ...
</template>


Suspense


Suspense 是一种特殊的 Vue 组件,用于解析有异步数据的组件。


比如:

<Suspense>
  <template #default>
    <AsyncComponent>
  </template>
  <template #fallback>
    Loading Data...
  </template>
</Suspense>


使用新的 Composition API,setup 可设置异步函数。Suspense 可以展示异步的模板直到 setup 被解析完。


实战代码:

<template>
  Welcome, {{user.name}}
</template>
<script>
  import { fetchUser } from '@/actions';
  export default {
    async setup() {
      const user = await fetchUser();
      return { user }
    }
  }
</script>
<Suspense>
  <template #default>
    <UserPanel/>
  </template>
  <template #fallback>
    Loading user ...
  </template>
</Suspense>


相关文章
|
24天前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
126 64
|
24天前
|
JavaScript 前端开发 API
Vue 3 中 v-model 与 Vue 2 中 v-model 的区别是什么?
总的来说,Vue 3 中的 `v-model` 在灵活性、与组合式 API 的结合、对自定义组件的支持等方面都有了明显的提升和改进,使其更适应现代前端开发的需求和趋势。但需要注意的是,在迁移过程中可能需要对一些代码进行调整和适配。
106 60
|
24天前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
29 8
|
23天前
|
存储 JavaScript 数据管理
除了provide/inject,Vue3中还有哪些方式可以避免v-model的循环引用?
需要注意的是,在实际开发中,应根据具体的项目需求和组件结构来选择合适的方式来避免`v-model`的循环引用。同时,要综合考虑代码的可读性、可维护性和性能等因素,以确保系统的稳定和高效运行。
25 1
|
23天前
|
JavaScript
Vue3中使用provide/inject来避免v-model的循环引用
`provide`和`inject`是 Vue 3 中非常有用的特性,在处理一些复杂的组件间通信问题时,可以提供一种灵活的解决方案。通过合理使用它们,可以帮助我们更好地避免`v-model`的循环引用问题,提高代码的质量和可维护性。
34 1
|
24天前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
|
1月前
|
JavaScript 索引
Vue 3.x 版本中双向数据绑定的底层实现有哪些变化
从Vue 2.x的`Object.defineProperty`到Vue 3.x的`Proxy`,实现了更高效的数据劫持与响应式处理。`Proxy`不仅能够代理整个对象,动态响应属性的增删,还优化了嵌套对象的处理和依赖追踪,减少了不必要的视图更新,提升了性能。同时,Vue 3.x对数组的响应式处理也更加灵活,简化了开发流程。
|
1月前
|
JavaScript 数据管理 Java
在 Vue 3 中使用 Proxy 实现数据双向绑定的性能如何?
【10月更文挑战第23天】Vue 3中使用Proxy实现数据双向绑定在多个方面都带来了性能的提升,从更高效的响应式追踪、更好的初始化性能、对数组操作的优化到更优的内存管理等,使得Vue 3在处理复杂的应用场景和大量数据时能够更加高效和稳定地运行。
61 1
|
28天前
|
JavaScript 前端开发 API
从Vue 2到Vue 3的演进
从Vue 2到Vue 3的演进
39 0
|
28天前
|
JavaScript 前端开发 API
Vue.js响应式原理深度解析:从Vue 2到Vue 3的演进
Vue.js响应式原理深度解析:从Vue 2到Vue 3的演进
54 0