初识vue3

1. 新建项目

vue create vue-study

2. 运行

yarn serve

语法

1. setup函数

可以取代data和method,相较于vue2,如果需要在template中使用的话,setup函数需要return。不需要再界面上暴露的变量就不需要return,精确控制导出的变量和方法

```javaScript
setup() {
    const girls = ref(["大脚", "刘英", "晓红"]);
    const selectGirl = ref("");
    // 使用ref,在script中使用/获取变量值需要加上value
    const selectGirlFun = (index: number) => {
        selectGirl.value = girls.value[index];
    };
    //因为在模板中这些变量和方法都需要调用,所以需要return出去。
    return {
        girls,
        selectGirl,
        selectGirlFun,
    };
}
```

2. ref函数

使用的话,需要引入`import { ref } from "vue";`,然后`ref(["大脚", "刘英", "晓红"])`

ref函数接收一个内部值,返回一个可响应且可变的对象,**在setup中,使用ref,要改变和读取一个值的时候,还要加上value**

3. reactive函数

是一个接收Object(对象)参数的函数,用于优化上述使用ref函数之后,改变和读取变量需要加上value的情况

和ref()函数一样,都是生成响应式对象的方法
```HTML
<button
    v-for="(item, index) in data.girls"
    v-bind:key="index"
    @click="data.selectGirlFun(index)"
    >
    {{ index }} : {{ item }}
</button>
<!-- 需要加上data.来调用 -->
<div>你选择了【{{ data.selectGirl }}】为你服务</div>
```

```JavaScript
// 记得加上类型注解
interface DataProps {
    girls: string[];
    selectGirl: string;
    selectGirlFun: (index: number) => void;
}

const data: DataProps = reactive({
    girls: ["大脚", "刘英", "晓红"],
    selectGirl: '',
    selectGirlFun: (index: number) => {
        // 修改值不需要加value了
        data.selectGirl = data.girls[index]
    }
});

// 只需要返回一个data
return {
    data,
};
```

4. toRefs()函数

使用reactive函数后,现在template中,每次输出变量前面都要加一个data,可以使用toRefs来优化

Vue3 的一个新函数toRefs(),引入后就可以对data进行包装,把 data 变成refData,这样就可以使用扩展运算符的方式了,否则直接使用扩展运算符会导致变量不可响应
```HTML
<button
  v-for="(item, index) in girls"
  v-bind:key="index"
  @click="selectGirlFun(index)"
>
  {{ index }} : {{ item }}
</button>
<div>你选择了【{{ selectGirl }}】为你服务</div>
```

```JavaScript
setup() {
    // const girls = ref(["大脚", "刘英", "晓红"]);
    // const selectGirl = ref("");
    // const selectGirlFun = (index: number) => {
    //   selectGirl.value = girls.value[index];
    // };
    const data: DataProps = reactive({
        girls: ["大脚", "刘英", "晓红"],
        selectGirl: "",
        selectGirlFun: (index: number) => {
            data.selectGirl = data.girls[index];
        },
    });
    const refData = toRefs(data);

    return {
        ...refData,
    };
},
```

5. 生命周期

1. setup函数 -> 开始创建组件之前,在`beforeCreate`和`created`之前,创建的是data和method。

可以使用setup函数来代替beforeCreatecreated
2. onBeforeMount -> 组件挂载到节点之前
3. onMounted -> 组件挂载到节点之后
4. onBeforeUpdate => 组件更新之前
5. onUpdated -> 组件更新之后
6. onBeforeUnmount -> 组件卸载之前
7. onUnmounted -> 组件卸载之后
8. onActivated -> 激活<keep-alive>组件时
9. onDeactivated -> 离开<keep-alive>组件时
10. onErrorCaptured -> 当捕获一个来自子孙组件的异常时激活钩子函数

在使用钩子函数之前,需要引入
```JavaScript
import {
    reactive,
    toRefs,
    onMounted,
    onBeforeMount,
    onBeforeUpdate,
    onUpdated,
} from "vue";

// 注意:vue3的这些钩子函数写在setup函数里面
setup() {
    console.log("1-开始创建组件-----setup()");
    const data: DataProps = reactive({
    girls: ["大脚", "刘英", "晓红"],
    selectGirl: "",
    selectGirlFun: (index: number) => {
        data.selectGirl = data.girls[index];
    },
    });
    onBeforeMount(() => {
        console.log("2-组件挂载到页面之前执行-----onBeforeMount()");
    });

    onMounted(() => {
        console.log("3-组件挂载到页面之后执行-----onMounted()");
    });
    onBeforeUpdate(() => {
        console.log("4-组件更新之前-----onBeforeUpdate()");
    });

    onUpdated(() => {
    c   onsole.log("5-组件更新之后-----onUpdated()");
    });

    const refData = toRefs(data);

    return {
    ...refData,
    };
},
```

Vue2的生命周期函数依然可以使用,可以写在setup函数后面
```JavaScript
setup() {
    ...
}
beforeCreate() {
    console.log("1-组件创建之前-----beforeCreate()");
},
beforeMount() {
    console.log("2-组件挂载到页面之前执行-----BeforeMount()");
},
mounted() {
    console.log("3-组件挂载到页面之后执行-----Mounted()");
},
beforeUpdate() {
    console.log("4-组件更新之前-----BeforeUpdate()");
},
updated() {
    console.log("5-组件更新之后-----Updated()");
},


// 以下是两个版本生命周期的对比
// 除了beforeDestroy -> onBeforeUnmount、destroyed -> onUnmounted,其他只是加了on
Vue2--------------vue3
beforeCreate  -> setup()
created       -> setup()
beforeMount   -> onBeforeMount
mounted       -> onMounted
beforeUpdate  -> onBeforeUpdate
updated       -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed     -> onUnmounted
activated     -> onActivated
deactivated   -> onDeactivated
errorCaptured -> onErrorCaptured
````

6. onRenderTracked()和onRenderTrigger()函数

用来调试使用的两个钩子函数。使用前需要引入
`import { onRenderTriggered ,onRenderTracked,} from "vue";`

onRenderTracked函数——状态追踪

它会追踪页面上**所有**响应式变量和方法的状态,即我们在setup中return出去的值,一旦页面有更新,他都会进行追踪,然后生成一个event对象,我们通过event对象来查找程序的问题所在

onRenderTriggered函数——状态触发

它不像onRenderTracked函数,这个函数不会跟踪所有值的变化,而是给你变化值的信息,并且新值和旧值都会给你明确的展示出来

```JavaScript
onRenderTracked((event) => {
    console.log("状态跟踪组件----------->");
    console.log(event);
});

onRenderTriggered((event) => {
    console.log("状态跟踪组件----------->");
    console.log(event);
});
```

其中`event`对象属性:
```
- key 那边变量发生了变化
- newValue 更新后变量的值
- oldValue 更新前变量的值
- target 目前页面中的响应变量和函数
```

7. watch函数

使用之前需要先导入 `import {... , watch} from "vue"`

以下是监听一个数和多个数的使用方式
```JavaScript
watch(overText, (newValue, oldValue) => {
    document.title = newValue;
});

// 注意:
// 当我们想监听data.selectGirl这个reactive里边的值时,可以使用一个函数来解决,() => data.selectGirl
// 监听多个数的变化,返回的newValue也是一个数组
watch([overText, () => data.selectGirl], (newValue, oldValue) => {
    console.log(`new--->${newValue}`);
    console.log(`old--->${oldValue}`);
    document.title = newValue[0]; // 返回的newValue也是一个数组
});
```

8. Vue3模块化

如果需要将一个功能进行模块化和复用化,可以在src目录下,新建一个文件夹hooks(所有抽离出来的功能模块都可以放到这个文件夹里),然后再新建一个文件useNowTime.ts,这里使用use开头是一个使用习惯,代表是一个抽离出来的模块。

```JavaScript
// 注意需要引入ref
import { ref } from "vue";

const nowTime = ref("00:00:00");
const getNowTime = () => {
    const now = new Date();
    const hour = now.getHours() < 10 ? "0" + now.getHours() : now.getHours();
    const minu =
        now.getMinutes() < 10 ? "0" + now.getMinutes() : now.getMinutes();
    const sec =
        now.getSeconds() < 10 ? "0" + now.getSeconds() : now.getSeconds();
    nowTime.value = hour + ":" + minu + ":" + sec;

    setTimeout(getNowTime, 1000);
};

// 最后export
export { nowTime, getNowTime }

// 引入和使用
import { nowTime, getNowTime } from "./hooks/useNowTime";
// 注意: 需要在setup中return,才可以在template中使用
setup() {
    return {nowTime,getNowTime};
}

```

远程调用API组件也可以这样子封装

9. Teleport瞬间移动组件的使用

它可以把你写的组件挂载到任何你想挂载的DOM上,在vue2中,所有dom都是挂载在#app下的,如果想改变节点这是非常的困难的。vue3的Teleport组件可以帮助解决这个问题。

Teleport方法,可以把Dialog组件渲染到你任意想渲染的外部Dom上,不必嵌套再#app里了,这样就不会互相干扰了。可以把Teleport看成一个传送门,把你的组件传送到你需要的地方。 teleport组件和其它组件没有任何其它的差异,用起来都是一样的。

使用方法如下:
```JavaScript
// Model.vue,自定义组件
// 将编写的组件用<teleport>标签进行包裹,在组件上有一个to属性,这个就是要写你需要渲染的DOMID了。
<template>
    <teleport to="#modal">
        <div id="center">
        <h2>JSPang11</h2>
        </div>
    </teleport>
</template>

// /public/index.html,在其中增加一个#model节点
<div id="app"></div>
<div id="modal"></div>

// App.vue,正常使用即可
<Modal></Modal>
```
这时候在浏览器中预览,就会发现,现在组件已经挂载到model节点上了,这就是teleport组件的使用了。

10. 初识Suspense组件

在Vue2.x时代,判断异步请求的状态是一件必须的事情,但是这些状态都要自己处理,根据请求是否完毕展示不同的界面,Vue3提供了Suspense组件来解决异步请求,页面渲染的问题

Suspense提供两个template的位置,一个是没有请求回来时显示的内容,一个是全部请求完毕的内容。这样进行异步内容的渲染就会非常简单。

**注意点:如果你要使用Suspense的话,要返回一个promise对象,而不是原来的那种JSON对象。**

以下为使用办法:
```JavaScript
// AsyncShow.vue,异步请求组件
// 2s之后页面出现JSPang文字
<template>
    <h1>{{ result }}</h1>
</template>
<script lang="ts">
    import { defineComponent } from "vue";
    // defineComponent是用来解决TypeScript情况下,传统的Vue.extends无法对组件给出正确的参数类型推断的。也就是说在TypeScript环境中如果参数类型推断不正常时,用defineComponent()组件来进行包装函数。
    export default defineComponent({
        setup() {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    return resolve({ result: "JSPang" });
                }, 2000);
            });
        },
    });
</script>

// App.vue
// 可以看到Suspense是有两个template插槽的,第一个default代表异步请求完成后,显示的模板内容。fallback代表在加载中时,显示的模板内容。
<template>
    <div>
        <Suspense>
            <template #default>
                <AsyncShow />
            </template>
            <template #fallback>
                <h1>Loading...</h1>
            </template>
        </Suspense>
    </div>
</template>
```

运行之后,如果一切正常,你可以看到,当我们打开页面时,首先显示的是Loading,然后才会显示JSPang。也就是promise返回的结果


- 在编写异步请求组件的时候,还可以通过 `async...await`的写法,它是`promise`的语法糖
```JavaScript
// AsyncShow.vue,异步请求组件
export default defineComponent({
    async setup() {  //promise 语法糖  返回之后也是promise对象
        const rawData = await  axios.get('https://apiblog.jspang.com/default/getGirl')
        return {result:rawData.data}
    }
})

```

Suspense组件加载多个异步组件的场景:

```JavaScript
<Suspense>
    <template #default>
        // 警告:是一个实验性的特性,它的API很可能会改变slots,除非只有一个根节点
        // 直接在Suspense组件下写两个异步组件会导致页面不显示
        <AsyncShow></AsyncShow>
        <AsyncShow2></AsyncShow2>
    </template>
    <template #fallback>
        <div>
        Loading... ---- 异步加载中
        </div>
    </template>
</Suspense>

// 解决办法
  <template #default>
    // 使用一个根节点包裹住,扩展一下,在<transition-group>组件中也是可以这样子解决
    <div>
        <AsyncShow></AsyncShow>
        <AsyncShow2></AsyncShow2>
    </div>
</template>
```

11. 处理异步请求错误

在异步请求中必须要作的一件事情,就是要捕获错误,因为我们没办法后端给我们返回的结果,也有可能服务不通,所以一定要进行捕获异常和进行处理。

在vue3.x的版本中,可以使用onErrorCaptured这个钩子函数来捕获异常。在使用这个钩子函数前,需要先进行引入
import { onErrorCaptured} from "vue";

有了onErrorCaptured就可以直接在setup()函数中直接使用了。钩子函数要求我们返回一个布尔值,代表错误是否向上传递,我们这里返回了true。

const app = {
  name: "App",
  components: { AsyncShow, GirlShow },
  setup() {
    onErrorCaptured((error) => {
      console.log(`error====>`,error)
      return true  
    })
    return {};
  },
};

参考

技术胖的vue3教程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容