vue 3.0

2021/04/11 vue 共 5888 字,约 17 分钟

背景

最近搭建的一个新项目用来vue3+vite,刚开始用的时候,可怀念vue2了,主要是懒得学习。但我还是用了vue3的语法,用着用着我发现真香。用vue3和vite结合的项目惊讶到我了。

什么是组合式 API

在开始写项目的时候,我一直没有get 到组合API的有点,还没有了全局的this,我就有点不开心了,但是随着项目越来越复杂,页面越来越大的时候我就发现组合API真香。特别喜欢。

就是以前数据方法一个放在data里面一个放在method里面,中间可能差了十万八千里,来回滚动看一些东西的时候就很不方便。有了组合api,这个问题就解决了。所有相关的都可以写在一块。真好。

由于在执行 setup 时,组件实例尚未被创建,因此在 setup 选项中没有 this。这意味着,除了 props 之外,你将无法访问组件中声明的任何属性——本地状态、计算属性或方法。setup 选项应该是一个接受 props 和 context 的函数

因为 props 是响应式的,你不能使用 ES6 解构,因为它会消除 prop 的响应性。如果需要解构需要用toRefs

执行 setup 时,组件实例尚未被创建。因此,你只能访问以下 property:

props attrs slots emit

换句话说,你将无法访问以下组件选项:

data computed methods

写 setup 我个人感觉就是和react如出一辙,所以上手一点都不难。他们很多思想几乎都一样,就是需看看vue都暴露了哪些方法供我们使用。这就完了,具体的暴露了哪些方法,怎么用,什么意思,我就不说了,自己慢慢看文档去吧。原来vue有的东西在组合api里面都有,只是需要我们一个一个单独引用

什么是组合式 API?

关于 watch 的东西

watch 监听的是响应式数据,如果我们监听的数据不是响应式的,watch 不能直接监听响应式对象的属性,如果我们非要监听响应式对象中的某个属性,我们可以使用 getter 函数的形式

watch( () => number.count, (newValue, oldValue) => { console.log(“新的值:”, newValue); console.log(“旧的值:”, oldValue); } );

watch 和 watchEffect 都能监听响应式数据的变化,不同的是它们监听数据变化的方式不同。

watch 会明确监听某一个响应数据,而 watchEffect 则是隐式的监听回调函数中响应数据。

watch 在响应数据初始化时是不会执行回调函数的,watchEffect 在响应数据初始化时就会立即执行回调函数。

一文搞懂Vue3中watch和watchEffect区别和用法!

新东西 Teleport

<teleport to="body">,可以告诉 Vue “Teleport 这个 HTML 该挂到‘body’标签”。 有了它,子组件就可以选择自己的父组件了,不必受限与在哪个组件使用。这个很棒,特别是对于一些全局弹窗,关于她的定位和宽高

Teleport 文档

Teleport API

JSX 这个语法第一次用

之前知道有这个东西,但是很少用,可能是我完美的避开了她的使用,又一次同事用到这个的时候,我才知道,原来他如此强。

this.$slots.default() 可以获取到所有插槽的内容,以前需要具名插槽才可以实现的,现在用它就灵活很多了。比如tab切换,tab及内容作为一个组件,因为tab名不确定,所以用具名插槽不灵活,可用jsx解决


<script lang="jsx">
  export default {
    props: {
      lazy: {
        type: Boolean,
        default: () => false,
      },
    },
    data() {
      return { 
        nav: [],
        active: 0
      }
    },
    mounted() {
      this.$nextTick(()=>{
        this.active = this.index
        this.nav = this.$slots.default().map((el,i)=>el.props||{name:'tab'+(i+1)});
        // 小提示:如果你没有用JXS的语法用的vue3的setup的话,获取子组建
        // context.solts.default().map((el,i)=>el.props||{name:'tab'+(i+1)})
        this.nav[this.active].show = true;
      })
    },
    methods: {
      change(index){
        this.active = index;
        this.nav[this.active].show = true;
        this.$emit("change",this.nav[this.active])
      }
    },
    render(){
      return (
        <div class="tabs">
          <div class="tab-nav">
            {
              this.nav.map((el,i)=><a class={`tab-item ${i===this.active?"active":""}`} onClick={e=>this.change(i)}>{el.name}</a>)
            }
          </div>
          <div class="tab-content">
              {
                this.$slots.default().map((item,i) => {
                  if (this.nav[i] && this.nav[i].show ) {
                    return <div class="tab-box" hidden={this.active!==i}>{item}</div>
                  }
                })
              }
          </div>
        </div>
      )
    }
  }
</script>

// 父组件使用
        <tab lazy
             @change="bookListHandler">
            <span name="tab1"></span>
            <span name="tab2"></span>
            <span name="tab3"></span>
        </tab>

模版语法JXS

vue3:个人建议呢多读读文档,发现新的东西尝试一下,会有新的收获的,祝好运

vue-router

Vue Router 和 组合式 API:在vue3中如何使用路由也是介绍的很清楚,很棒

createWebHistory('/folder/') 这个也很棒,解决了我项目中的一个场景

场景描述:所有的路由前面动态的加入一个参数,这个参数不固定,比如可能出现的情况 https://example.com/folder/xxx ,https://example.com/app/xxx,https://example.com/web/xxx,因为第一个参数不固定是用户自己填写的,如果按照传统的形式,我们需要修改路由表及其业务代码

const routes = [
  { path: '/:flag/index', component: Index },
  { path: '/:flag/about', component: About },
  { path: '/:flag/home', component: Home },
  { path: '/:flag/center', component: Center },
]

对应的业务中还需要使用 location.pathname 去获取第一个参数的名字,然后塞到路由的挑战里面去,一看就是很不方便,增加了很多没有必要的业务,而且日后维护也很不方便。

如果是几十个页面每个页面都写,很累的,而且工作量很大,但是有我前面说的api就很方便了

createWebHistory(location.pathname.split(‘/’)[0]) // 给出的网址为 https://example.com/folder/xxxx,会动态的配置了,我们路由规则也很简单了

const routes = [
  { path: '/index', component: Index },
  { path: '/about', component: About },
  { path: '/home', component: Home },
  { path: '/center', component: Center },
]

是不是很棒呀 ['s v-slot](https://next.router.vuejs.org/api/index.html#router-link-s-v-slot)是一个很棒的东西,可以试一试

新版的 router 支持了路由参数自定义正则和可重复的参数,虽然我还没有用到,但是感觉很灵活,应该很好用的

const routes = [
  // /:orderId -> 仅匹配数字
  { path: '/:orderId(\\d+)' },
  // /:productName -> 匹配其他任何内容
  { path: '/:productName' },
]

现在,转到 /25 将匹配 /:orderId,其他情况将会匹配 /:productName。routes 数组的顺序并不重要!

const routes = [
  // /:chapters ->  匹配 /one, /one/two, /one/two/three, 等
  { path: '/:chapters+' },
  // /:chapters -> 匹配 /, /one, /one/two, /one/two/three, 等
  { path: '/:chapters*' },
]

如果你需要匹配具有多个部分的路由,如 /first/second/third,你应该用 *(0 个或多个)和 +(1 个或多个)将参数标记为可重复:

const routes = [
  // 仅匹配数字
  // 匹配 /1, /1/2, 等
  { path: '/:chapters(\\d+)+' },
  // 匹配 /, /1, /1/2, 等
  { path: '/:chapters(\\d+)*' },
]
const routes = [
  // 匹配 /users 和 /users/posva
  { path: '/users/:userId?' },
  // 匹配 /users 和 /users/42
  { path: '/users/:userId(\\d+)?' },
]

请注意,* 在技术上也标志着一个参数是可选的,但 ? 参数不能重复。

路由的匹配语法

浏览器自己本身就有路由,为什么不直接用a标签进行一个跳转,而是选择用router来进行一个跳转呢

a标签的跳转是通过HTTP协议的GET请求来实现的。这种方式虽然简单,但每次访问都需要从服务器下载完整的页面,这会耗费时间和带宽,同时也会带来加载时的白屏问题,还会导致页面刷新,这会给用户带来一些不好的体验

使用前端路由(比如Vue Router)可以实现单页应用,避免每次访问都要从服务器下载完整的页面,在局部刷新的同时保持页面状态,提高了网站的性能和用户体验。

vue的history模式和hash模式的区别是什么?

hash 模式:URL 中带有 # 号,例如:http://www.example.com/#/user。Hash 模式在 URL 中的 # 符号后面的部分被称为哈希值,不会向服务器发送请求,而是在页面中通过 JavaScript 监听 URL 的改变,从而实现单页应用的路由。它的优点是实现起来简单,支持在旧版浏览器中使用。缺点是在 URL 中会带有 # 符号,不太美观,并且在 SEO 方面存在一些问题。通过监听浏览器的 hashchange 事件

history 模式:URL 中不含有 # 号,例如:http://www.example.com/user。History 模式通过 HTML5 History API 中的 pushState 和 replaceState 方法来实现 URL 的改变,与 hash 模式不同的是,history 模式会向服务器发送请求,需要服务器的支持才能正常运行。它的优点是 URL 简洁美观,不存在 hash 符号,并且在 SEO 方面也有一定的优势。缺点是在旧版浏览器中无法使用,在实现起来也相对比较困难。

总体来说,如果你的项目不需要考虑 SEO 优化,或者需要支持旧版浏览器,那么可以选择 hash 模式;如果你需要考虑 SEO 优化,或者只需要支持现代浏览器,那么可以选择使用 history 模式。

vite

【译】下一代前端工具 ViteJS 中英双语字幕 - Open Source Friday 我认真的看完这个视频之后我发现vite的强大远远超出我的想象。vite没有框架的限制,任何前端项目只要你想用都可。就连简单html都可以当一个服务器启动,只需要你安装vite,即可

vite demo 实践

vite惊讶到我的是,我修改了配置文件也可以实时更新,不需要重新启动项目,这个是vue-cli所不能做到了。启动速度打包速度也很快,惊讶到我了,很喜欢。

部署静态站点

{
  "scripts": {
    "build": "vite build",
    "preview": "vite preview" 
  }
}

怪我愚蠢,最开始没有细细读文档yarn preview 是什么意思没有读懂,后来我知道了。当我知道之后我发现它真香,惊艳到我了

当你构建完成应用后,你可以通过运行 npm run preview 命令,在本地测试该应用。

preview 命令会启动一个本地静态 Web 服务器,将 dist 文件夹运行在 http://localhost:5000 上 。这样在本地查看该产物是否正常可用就十分容易了。

你可以使用 –port 标志传入一个参数来配置服务器的运行端口。


{
  "scripts": {
    "preview": "vite preview --port 8080"
  }
}

这样 preview 命令会改将服务器运行在 http://localhost:8080 上。

部署静态站点

打包以后的文件可以在本地运行,这个就很不错了,可以不用发到服务看最后的结果。

注意:这个需要访问服务器api的时候,把这个api的全地址打在包里面,而不是使用相对路径,因为打包后没有了反响代理

vite很不错,推荐先看一下文档,然后在看网上的总结

vite 文档

备战2021:vite工程化实践,建议收藏

备战2021:Vite2项目最佳实践

【译】下一代前端构建工具 ViteJS 中英双语字幕 | 技术点评

【译】下一代前端工具 ViteJS 中英双语字幕 - Open Source Friday

参考文章

忙了一夜用CompositionAPI征服产品妹子花里胡哨的需求

闪电五连鞭:Composition API原理深度剖析

不要再用Vue 2的思维写Vue 3了


在技术的历史长河中,虽然我们素未谋面,却已相识已久,很微妙也很知足。互联网让世界变得更小,你我之间更近。

在逝去的青葱岁月中,虽然我们未曾相遇,却共同经历着一样的情愫。谁的青春不曾迷茫或焦虑亦是无奈,谁不曾年少过

在未来的日子里,让我们共享好的文章,共同学习进步。有不错的文章记得分享给我,我不会写好的文章,所以我只能做一个搬运工

我叫 sunseekers(张敏) ,千千万万个张敏与你同在,18年电子商务专业毕业,毕业后在前端搬砖

如果喜欢我的话,恰巧我也喜欢你的话,让我们手拉手,肩并肩共同前行,相互学习,互相鼓励

文档信息

Search

    Table of Contents