Vue 3已经发布了一年,它的主要新功能是:Composition API。从2021年秋季开始,推荐新项目使用Vue 3的 script setup 语法,所以希望我们能看到越来越多的生产级应用程序建立在Vue 3上。
这篇文章旨在展示一些有趣的方法来利用Composition API,以及如何围绕它来构造一个应用程序。
新的组合API释放了许多有趣的方法来重用跨组件的代码。复习一下:以前我们根据组件选项API分割组件逻辑:data、methods、created 等。
// 选项API风格
data: () => ({
refA: 1,
refB: 2,
}),
// 在这里,我们经常看到500行的代码。
computed: {
computedA() {
return this.refA + 10;
},
computedB() {
return this.refA + 10;
},
},
有了Composition API,我们就不会受限于这种结构,可以根据功能而不是选项来分离代码。
setup() {
const refA = ref(1);
const computedA = computed(() => refA.value + 10);
/*
这里也可能是500行的代码。
但是,这些功能可以保持在彼此附近!
*/
const computedB = computed(() => refA.value + 10);
const refB = ref(2);
return {
refA,
refB,
computedA,
computedB,
};
},
Vue 3.2引入了<script setup>语法,这只是setup()函数的语法糖,使代码更加简洁。从现在开始,我们将使用 script setup 语法,因为它是最新的语法。
<script setup>
import { ref, computed } from 'vue'
const refA = ref(1);
const computedA = computed(() => refA.value + 10);
const refB = ref(2);
const computedB = computed(() => refA.value + 10);
</script>
在我看来,这是一个比较大想法。我们可以把这些功能分成自己的文件,而不是用通过放置 在script setup中的位置来保持它们的分离。下面是同样的逻辑,把文件分割开来的做法。
// Component.vue
<script setup>
import useFeatureA from "./featureA";
import useFeatureB from "./featureB";
const { refA, computedA } = useFeatureA();
const { refB, computedB } = useFeatureB();
</script>
// featureA.js
import { ref, computed } from "vue";
export default function () {
const refA = ref(1);
const computedA = computed(() => refA.value + 10);
return {
refA,
computedA,
};
}
// featureB.js
import { ref, computed } from "vue";
export default function () {
const refB = ref(2);
const computedB = computed(() => refB.value + 10);
return {
refB,
computedB,
};
}
注意,featureA.js和featureB.js导出了Ref和ComputedRef类型,因此所有这些数据都是响应式的。
然而,这个特定的片段可能看起来有点矫枉过正。
如果生命周期钩子(onMounted,onUpdated等)可以在setup里面使用,这也意味着我们也可以在我们的可组合函数里面使用它们。甚至可以这样写:
// Component.vue
<script setup>
import { useStore } from 'vuex';
const store = useStore();
store.dispatch('myAction');
</script>
// store/actions.js
import { onMounted } from 'vue'
// ...
actions: {
myAction() {
onMounted(() => {
console.log('its crazy, but this onMounted will be registered!')
})
}
}
// ...
而且Vue甚至会在vuex内部注册生命周期钩子!
有了这种灵活性,了解如何以及何时注册这些钩子就很重要了。请看下面的片段。哪些onUpdated钩子将被注册?
<script setup lang="ts">
import { ref, onUpdated } from "vue";
// 这个钩子将被注册。我们在 setup 中正常调用它
onUpdated(() => {
console.log(':white_check_mark:')
});
class Foo {
constructor() {
this.registerOnMounted();
}
registerOnMounted() {
//它也会注册! 它是在一个类方法中,但它是在
//在 setup 中同步执行
onUpdated(() => {
console.log(':white_check_mark:')
});
}
}
new Foo();
// IIFE also works
(function () {
onUpdated(() => {
state.value += ":white_check_mark:";
});
})();
const onClick = () => {
/*
这不会被注册。这个钩子是在另一个函数里面。
Vue不可能在setup 初始化中达到这个方法。
最糟糕的是,你甚至不会得到一个警告,除非这个
函数被执行! 所以要注意这一点。
*/
onUpdated(() => {
console.log(':x:')
});
};
// 异步IIFE也会不行 :(
(async function () {
await Promise.resolve();
onUpdated(() => {
state.value += ":x:";
});
})();
</script>
结论:在声明生命周期方法时,应使其在setup初始化时同步执行。否则,它们在哪里被声明以及在什么情况下被声明并不重要。
我们经常需要在我们的逻辑中使用async/await。天真的做法是尝试这样做:
<script setup lang="ts">
import { myAsyncFunction } from './myAsyncFunction.js
const data = await myAsyncFunction();
</script>
<template>
Async data: {{ data }}
</template>
然而,如果我们尝试运行这段代码,组件根本不会被渲染。为什么?因为 Promise 不跟踪状态。我们给 data 变量赋了一个 promise,但是Vue不会主动更新它的状态。幸运的是,有一些变通办法:
为了渲染该组件,我们可以使用.then语法。
<script setup>
import { ref } from "vue";
import { myAsyncFunction } from './myAsyncFunction.js
const data = ref(null);
myAsyncFunction().then((res) =>
data.value = fetchedData
);
</script>
<template>
Async data: {{ data }}
</template>
这种方式有自己优缺点:
如果我们把这个逻辑包在一个异步IIFE里面,我们就可以使用 async/await的语法。
<script setup>
import { ref } from "vue";
import { myAsyncFunction } from './myAsyncFunction.js'
const data = ref(null);
(async function () {
data.value = await myAsyncFunction()
})();
</script>
<template>
Async data: {{ data }}
</template>
这种方式也有自己优缺点:
如果我们在父组件中用<Suspense>包装这个组件,我们就可以自由在setup 中自由使用async/await!
// Parent.vue
<script setup lang="ts">
import { Child } from './Child.vue
</script>
<template>
<Suspense>
<Child />
</Suspense>
</template>
// Child.vue
<script setup lang="ts">
import { myAsyncFunction } from './myAsyncFunction.js
const data = await myAsyncFunction();
</script>
<template>
Async data: {{ data }}
</template>
<Suspense> 组件在子组件 setup 中有更多的可能性,而不仅仅是异步。使用它,我们还可以指定加载和回退状态。我认为这是创建异步组件的前进方向。Nuxt 3已经使用了这个特性,对我来说,一旦这个特性稳定下来,它可能是首选的方式。
优点。最灵活。
缺点:对package.json的依赖。
VueUse库依靠Composition API解锁的新功能,给出了各种辅助函数。就像我们写的 useFeatureA 和 useFeatureB 一样,这个库可以让我们导入预制的实用函数,以可组合的风格编写。下面是它的工作原理的一个片段。
<script setup lang="ts">
import {
useStorage,
useDark
} from "@vueuse/core";
import { ref } from "vue";
/*
一个实现localStorage的例子。
这个函数返回一个Ref,所以可以立即用`.value`语法来编辑它。
用.value语法编辑,而不需要单独的getItem/setItem方法。
*/
const localStorageData = useStorage("foo", undefined);
</script>
我无法向你推荐这个库,在我看来,它是任何新的Vue 3项目的必备品。
下面是这个库如何解决前面提到的异步调用执行问题。
<script setup>
import { useAsyncState } from "@vueuse/core";
import { myAsyncFunction } from './myAsyncFunction.js';
const { state, isReady } = useAsyncState(
// the async function we want to execute
myAsyncFunction,
// Default state:
"Loading...",
// UseAsyncState options:
{
onError: (e) => {
console.error("Error!", e);
state.value = "fallback";
},
}
);
</script>
<template>
useAsyncState: {{ state }}
Is the data ready: {{ isReady }}
</template>
这种方法可以让你在setup里面执行异步函数,并给你回退选项和加载状态。现在,这是我处理异步的首选方法。
新的defineProps和defineEmits语法
script setup 带来了一种在Vue组件中输入 props 和 emits 的更快方式。
<script setup lang="ts">
import { PropType } from "vue";
interface CustomPropType {
bar: string;
baz: number;
}
// defineProps的重载。
// 1. 类似于选项API的语法
defineProps({
foo: {
type: Object as PropType<CustomPropType>,
required: false,
default: () => ({
bar: "",
baz: 0,
}),
},
});
// 2. 通过一个泛型。注意,不需要PropType!
defineProps<{ foo: CustomPropType }>();
// 3.默认状态可以这样做。
withDefaults(
defineProps<{
foo: CustomPropType;
}>(),
{
foo: () => ({
bar: "",
baz: 0,
}),
}
);
// // Emits也可以用defineEmits进行简单的类型化
defineEmits<{ (foo: "foo"): string }>();
</script>
就个人而言,我会选择通用风格,因为它为我们节省了一个额外的导入,并且对null和 undefined 的类型更加明确,而不是Vue 2风格语法中的{ required: false }。
注意,不需要手动导入 defineProps 和 defineEmits。这是因为这些是Vue使用的特殊宏。这些在编译时被处理成 "正常 的选项API语法。我们可能会在未来的Vue版本中看到越来越多的宏的实现。
因为typescript要求默认输入模块的返回值,所以一开始我主要是用这种方式写TS组合物。
import { ref, Ref, SetupContext, watch } from "vue";
export default function ({
emit,
}: SetupContext<("change-component" | "close")[]>):
// 下面的代码真的有必要吗?
{
onCloseStructureDetails: () => void;
showTimeSlots: Ref<boolean>;
showStructureDetails: Ref<boolean>;
onSelectSlot: (arg1: onSelectSlotArgs) => void;
onBackButtonClick: () => void;
showMobileStepsLayout: Ref<boolean>;
authStepsComponent: Ref<string>;
isMobile: Ref<boolean>;
selectedTimeSlot: Ref<null | TimeSlot>;
showQuestionarireLink: Ref<boolean>;
} {
const isMobile = useBreakpoints().smaller("md");
const store = useStore();
// and so on, and so on
// ...
}
这种方式,我认为这是个错误。其实没有必要对函数返回进行类型化,因为在编写可组合的时候可以很容易地对它进行隐式类型化。它可以为我们节省大量的时间和代码行。
import { ref, Ref, SetupContext, watch } from "vue";
export default function ({
emit,
}: SetupContext<("change-component" | "close")[]>) {
const isMobile = useBreakpoints().smaller("md");
const store = useStore();
// The return can be typed implicitly in composables
}
如果EsLint将此标记为错误,将'@typescript-eslint/explicit-module-boundary-types': 'error',放入EsLint配置(.eslintrc)。
Volar是作为VsCode和WebStorm的Vue扩展来取代Vetur的。现在它被正式推荐给Vue 3使用。对我来说,它的主要特点是:typing props and emits out of the box。这很好用,特别是使用Typescript的话。
现在,我总是会选择Vue 3项目中使用Volar。对于Vue 2, Volar仍然适用,因为它需要更少的配置 。
以前,有一些例子,所有的逻辑都是在script setup 中完成的。还有一些例子是使用从.vue文件导入的可组合函数的组件。
大代码设计问题是:我们应该把所有的逻辑写在.vue文件之外吗?有利有弊。
所有的逻辑都放在 setup中 | 移到专用的.js/.ts文件 |
不需要写一个可组合的,方便直接修改 | 可扩展更强 |
重用代码时需要重构 | 不需要重构 |
更多模板 |
我是这样选择的:
来源: 大迁世界
在 Native 开发中,Android 和 IOS 平台都在系统层面直接提供给了应用开发识别图像的一些能力,比如对于二维码/条形码的识别,Android 可以使用 barcode API 、 iOS 可以使用 CIQRCodeFeature API 。
Js的API设计原则总共包含了七个大块。系卤煮自己总结的一些经验和教训。本篇博文同时也参考了其他一些文章,相关地址会在后面贴出来。很难做到详尽充实,如果有好的建议或者不对的地方,还望不吝赐教斧正。
现在越来越流行前后端分离开发,使用ajax交互。所以api接口文档就变的十分有意义了,目前市场有哪些比较优秀的接口文档管理工具呢?比如:MinDoc,eoLinker,apizza,RAML,Swagger等等
无论网站,还是App目前基本都是基于api接口模式的开发,那么api的安全就尤为重要了。目前攻击最常见的就是“短信轰炸机”,由于短信接口验证是App,网站检验用户手机号最真实的途径,使用短信验证码在提供便利的同时,也成了呗恶意攻击的对象,那么如何才能防止被恶意调用呢?
整理提供最新的各种免费JSON接口,其中有部分需要用JSONP调用。方面前端同学的学习或在网站中的使用,包括:免费的天气预报、地图、IP、手机信息查询、翻译、新闻等api接口
要弄清楚什么是RESTful API,首先要弄清楚什么是REST。REST -- REpresentational State Transfer,英语的直译就是“表现层状态转移”。如果看这个概念,估计没几个人能明白是什么意思。
Fetch API 已经作为现代浏览器中异步网络请求的标准方法,其使用 Promise 作为基本构造要素。Fetch 在主流浏览器中都有很好的支持,除了IE。
随着移动互联网的发展, 基于互联网的应用正变得越来越普及,在这个过程中,更多的平台将自身的资源开放给开发者来调用。对外提供的API 调用使得平台之间的内容关联性更强,同时这些开放的平台也为用户、开发者和中小网站带来了更大的价值。
环境centos,添加deamon.json后,dockerd命令可以启动docker,这时请求 127.0.0.1:2375 可以正常访问,使用systemctl无法启动docker的情况.无法启动docker:查看当前的docker配置
你是否正在设计第一个Web应用程序?也许你过去已经建立了一些,但是目前也正在寻找语言的变化以提高你的技能,或尝试新的东西。有了所有信息,就很难决定为下一个产品或项目选择哪种编程语言。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!