Book delivery activity: choose 1 fan classmate and send it free of charge.
Deadline: 19:00 on May 26, 2023
Participate in the comment area at the bottom and talk : Please share your reading gains in the comments.
Notes on China-Taiwan Landing——Business Servitization and Data Assetization
vue-i18n-next
To use i18n in vue3, you need to install the version [vue-i18n v9]
npm install vue-i18n@9
Create src\lang\index.ts and createI18n
create an i18n instance with:
// src\lang\index.ts
import { createI18n } from 'vue-i18n'
import { LANG_VALUE } from '@/common/enum'
import ch from './ch'
import en from './en'
const i18n = createI18n({
legacy: false,
locale: getLanguage(),
messages: {
[LANG_VALUE.ch]: ch,
[LANG_VALUE.En]: en
}
})
export default i18n
If you are using the Composition API, you need to define it as false
locale : The current language to be displayed. The value is the previous user's language selection, read from the browser cache. If there is no data in the cache, by
navigator.language
getting the language used by the browser:
// src\lang\index.ts
import { localCache } from '@/utils'
export function getLanguage() {
const chooseLanguage = localCache.getItem(LANGUAGE)
if (chooseLanguage) return chooseLanguage
// 如果没有选择语言
const language = navigator.language.toLowerCase()
const locales = [LANG_VALUE.En, LANG_VALUE.Zh]
for (const locale of locales) {
if (language.indexOf(locale) > -1) {
return locale
}
}
return LANG_VALUE.Zh
}
// src\common\enum.ts
export enum LANG_VALUE {
En = 'en',
Zh = 'zh-Hans'
}
messages : Translation files corresponding to different languages:
// src\lang\zh-Hans.ts
export default {
baoguochuku: '包裹出库',
sousuo: '搜索'
}
// src\lang\en.ts
export default {
baoguochuku: 'Outbound',
sousuo: 'Search'
}
// src\main.ts,省略其它代码
import i18n from './lang/index'
app.use(i18n)
Import from vue-i18n useI18n
, then call to generate i18n
an instance, and then deconstruct t
the method from it
<template>
used in
<template>
<n-button>
<slot name="submitBtnText">{
{ $t('xxx') }}</slot>
</n-button>
</template>
It is used directly $t
because there is a globalInjection
configuration item called by default true
, which helps us inject $t
the method globally. If it is set to false
:
// src\lang\index.ts
const i18n = createI18n({
globalInjection: false
})
In the ts file, configure the generated i18n
instance in src\lang\index.ts
// src\service\request\index.ts
import i18n from '@/lang'
if (!axios.isCancel(error)) {
dialog.error({
title: i18n.global.t('biaoti'),
// ...
})
}
import { watch, ref } from 'vue'
setup() {
let mes = ref('会好的')
//第一种情况 监听ref定义的一个响应式数据
watch(mes, (qian, hou) => {
console.log('变化----', qian, hou)
}, {immediate: true})
}
setup() {
let mes = ref('会好的')
let mess = ref('我是谁')
//第二种情况 监听ref定义的多个响应式数据
watch([mes,mess], (qian, hou) => {
console.log('变化----', qian, hou)
},{immediate:true})
}
setup() {
let rea=reactive({
name:'我是谁',
obj:{
salary:20
}
})
//第三种情况 监听reactive定义的属性
watch(rea,(qian,hou)=>{
console.log('rea变化了',qian,hou)
})
}
stop listening
const stop = watchEffect(() => {
/* ... */
})
// later
stop()
const data = ref(null)
watchEffect(async onInvalidate => {
onInvalidate(() => {
/* ... */
}) // 我们在Promise解析之前注册清除函数
data.value = await fetchData(props.id)
})
watch can access new and old values, watchEffect cannot.
watchEffect has side effects, which will be triggered before the DOM is mounted or updated , and we need to clear the side effects ourselves.
Watch is lazy execution , that is, it will only be executed when the monitored value changes, but watchEffect is different, and watchEffect will be executed every time the code is loaded .
Watch needs to specify the object to monitor, and also needs to specify the callback to monitor. watchEffect does not need to specify which attribute to monitor, which attribute is used in the monitoring callback function, and which attribute is monitored.
It is recommended to use vscode and install the volar plug-in to assist development
<template>
<div>{
{ numberRef }}</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const numberRef = ref(0) // ===> Ref<number>
const stringRef = ref("") // ===> Ref<string>
interface IFoo {
bar: string
}
const fooRef = ref<IFoo>() // ===> Ref<IFoo | undefined>
</script>
<template>
<div>{
{ book1.bar }}</div>
</template>
<script setup lang="ts">
import { reactive } from 'vue';
interface IFoo {
bar: string
}
// 第一种
const book1 = reactive<IFoo>({ bar: 'bar' })
// 第二种
const book2: IFoo = reactive({ bar: 'bar' })
// 第三种
const book3 = reactive({ bar: 'bar' }) as IFoo
</script>
<template>
<div>{
{ fooComputed?.bar }}</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
const numberRef = ref(0) // ===> Ref<number>
const numberComputed = computed(() => numberRef.value) // ===> ComputedRef<number>
interface IFoo {
bar: string
}
const fooRef = ref<IFoo>() // ===> Ref<IFoo | undefined>
const fooComputed = computed(() => {
return fooRef.value
}) // ===> ComputedRef<IFoo | undefined>
</script>
<template>
<div>{
{ fooComputedWritable?.bar }}</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
interface IFoo {
bar: string
}
const fooRef = ref<IFoo>() // ===> Ref<IFoo | undefined>
const fooComputedWritable = computed({
get: () => {
return fooRef.value
},
set: (value) => {
fooRef.value = value
}
}) // ===> WritableComputedRef<IFoo | undefined>
</script>
<template>
<div>{
{ numberRef }}</div>
</template>
<script setup lang="ts">
import { ref, watch, watchEffect } from 'vue';
const numberRef = ref(0) // ===> Ref<number>
interface IFoo {
bar: string
}
const fooRef = ref<IFoo>() // ===> Ref<IFoo | undefined>
watchEffect(() => console.log(fooRef.value?.bar))
watch(numberRef, () => {
console.log(`numberRef变化了`)
})
const stop = watch(fooRef, () => {
console.log(`fooRef变化了`)
}, {
deep: true
}) // 检查深度嵌套的对象或数组
stop(); // 停止侦听
</script>
<template>
<div></div>
</template>
<script setup lang="ts">
import { nextTick } from 'vue';
nextTick(() => {
// ...
})
// 还可以使用 async/await
async () => {
await nextTick()
// ....
}
</script>
<template>
<Foo></Foo>
<foo-item></foo-item>
<component :is="Foo" />
<component :is="someCondition ? Foo : FooItem" />
</template>
<script setup lang="ts">
import Foo from "./Foo.vue"
import FooItem from "./FooItem.vue"
const someCondition = false
</script>
<template>
<div>
<!-- 直接使用即可,不需要toRefs转换 -->
{
{ foo }}
</div>
</template>
<script setup lang="ts">
import { toRefs } from 'vue';
interface ICustomType {
foo: string,
bar: string
}
const props = defineProps({
foo: String, // 使用构造函数声明类型
fooMultiTypes: [String, Number], // 多个类型
fooCustomType: Object as () => ICustomType, // 自定义类型
fooCustomTypeWithRequire: {
type: Object as () => ICustomType,
required: true
}, // 自定义类型,必选
fooCustomTypeWithDefault: {
type: Object as () => ICustomType,
default: () => {
return {
foo: "foo",
bar: "bar"
}
}
}, // 自定义类型,带默认值
})
// 1. 可以在模板<template>中使用声明的props,不需要用toRefs转换
// 2. 如果某一个值需要在setup中使用,则需要用toRefs转换下,然后把它解构出来
const {
foo, // ===> Ref<string | undefined> | undefined
fooMultiTypes, // ===> Ref<string | number | undefined> | undefined
fooCustomType, // ===> Ref<ICustomType | undefined> | undefined
fooCustomTypeWithRequire, // ===> Ref<ICustomType>
} = toRefs(props)
</script>
<template>
<div>
<!-- 直接使用即可,不需要toRefs转换 -->
{
{ foo }}
</div>
</template>
<script setup lang="ts">
import { toRefs } from 'vue';
interface ICustomType {
foo: string,
bar: string
}
const props = defineProps<{
foo?: string,
fooWithRequire: string,
fooMultiTypes: string | number,
fooCustomType?: ICustomType,
fooCustomTypeWithRequire: ICustomType
}>()
// 泛型方式声明默认值,需要使用withDefaults 编译器宏
const propsWithDefault = withDefaults(
defineProps<{
fooCustomTypeWithDefault: ICustomType
}>(),
{
fooCustomTypeWithDefault: () => {
return {
foo: "foo",
bar: "bar"
}
}
})
// 1. 可以在模板<template>中使用声明的props,不需要用toRefs转换
// 2. 如果某一个值需要在setup中使用,则需要用toRefs转换下,然后把它解构出来
const {
foo, // ===> Ref<string | undefined> | undefined
fooWithRequire, // ===> Ref<string>
fooMultiTypes, // ===> Ref<string | number>
fooCustomType, // ===> Ref<ICustomType | undefined> | undefined
fooCustomTypeWithRequire, // ===> Ref<ICustomType>
} = toRefs(props)
const {
fooCustomTypeWithDefault, // ===> Ref<ICustomType>
} = toRefs(propsWithDefault)
</script>
// FooBar.vue
<template>
<div>
<!-- 一个单文件组件可以通过它的文件名被其自己所引用 -->
<FooBar></FooBar>
<foo-bar></foo-bar>
<foo-bar-other></foo-bar-other>
</div>
</template>
<script setup lang="ts">
// 使用 import 别名导入避免冲突
import { default as FooBarOther } from './others/FooBar.vue'
</script>
<template>
<div></div>
</template>
<script setup lang="ts">
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
onErrorCaptured,
onRenderTracked,
onRenderTriggered,
onActivated,
onDeactivated
} from "vue"
// 直接使用就好了
onMounted(() => {
// ...
})
</script>
<template>
<div></div>
</template>
<script setup lang="ts">
import { provide } from 'vue';
export interface IUser {
name: string,
age: number
}
provide("name", "foo")
provide<IUser>("user", {
name: "foo",
age: 23
})
</script>
<template>
<div></div>
</template>
<script setup lang="ts">
import { inject } from 'vue';
import { IUser } from './Foo.vue';
const name = inject<string>("name") // ===> string | undefined
const user = inject<IUser>("user") // ===> IUser | undefined
</script>
import { createApp } from 'vue';
import App from './App.vue'
createApp(App).mount('#app')
Using the import and export syntax of import
and export
, the function of packaging modules on demand is realized, and the file size of the packaged project is significantly smaller.
<template>
<div id="app">
<p>{
{ number }}</p>
<button @click="add">增加</button>
</div>
</template>
<script>
// 1. 从 vue 中引入 ref 函数
import {ref} from 'vue'
export default {
name: 'App',
setup() {
// 2. 用 ref 函数包装一个响应式变量 number
let number = ref(0)
// 3. 设定一个方法
function add() {
// number是被ref函数包装过了的,其值保存在.value中
number.value ++
}
// 4. 将 number 和 add 返回出去,供template中使用
return {number, add}
}
}
</script>
setup
The function also has two parameters, respectively props
, context
, the former stores the parameter names and corresponding values that define the current component that allows the outside world to pass over; the latter is a context object, from which you can access attr
, emit
,slots
<template>
<div id="app"></div>
</template>
<script>
// 1. 从 vue 中引入 多个生命周期函数
import {onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, unMounted} from 'vue'
export default {
name: 'App',
setup() {
onBeforeMount(() => {
// 在挂载前执行某些代码
})
onMounted(() => {
// 在挂载后执行某些代码
})
onBeforeUpdate(() => {
// 在更新前前执行某些代码
})
onUpdated(() => {
// 在更新后执行某些代码
})
onBeforeUnmount(() => {
// 在组件销毁前执行某些代码
})
unMounted(() => {
// 在组件销毁后执行某些代码
})
return {}
}
}
</script>
reactive
The method is used to create a responsive data object, and this API also solves defineProperty
the defect of Vue2 by implementing data responsiveness
<template>
<div id="app">
<!-- 4. 访问响应式数据对象中的 count -->
{
{ state.count }}
</div>
</template>
<script>
// 1. 从 vue 中导入 reactive
import {reactive} from 'vue'
export default {
name: 'App',
setup() {
// 2. 创建响应式的数据对象
const state = reactive({count: 3})
// 3. 将响应式数据对象state return 出去,供template使用
return {state}
}
}
</script>
.value
It needs to be added when accessing the wrapped object setup
in the function , and it is not needed when accessing in the template, because it will automatically recognize whether it is wrapped when compiling ref
template
ref
<script>
// 1. 导入 toRef
import {toRef} from 'vue'
export default {
setup() {
const obj = {count: 3}
// 2. 将 obj 对象中属性count的值转化为响应式数据
const state = toRef(obj, 'count')
// 3. 将toRef包装过的数据对象返回供template使用
return {state}
}
}
</script>
<script>
// 1. 导入 ref
import {ref} from 'vue'
export default {
setup() {
const obj = {count: 3}
// 2. 将 obj 对象中属性count的值转化为响应式数据
const state = ref(obj.count)
// 3. 将ref包装过的数据对象返回供template使用
return {state}
}
}
</script>
<template>
<p>{
{ state1 }}</p>
<button @click="add1">增加</button>
<p>{
{ state2 }}</p>
<button @click="add2">增加</button>
</template>
<script>
import {ref, toRef} from 'vue'
export default {
setup() {
const obj = {count: 3}
const state1 = ref(obj.count)
const state2 = toRef(obj, 'count')
function add1() {
state1.value ++
console.log('原始值:', obj);
console.log('响应式数据对象:', state1);
}
function add2() {
state2.value ++
console.log('原始值:', obj);
console.log('响应式数据对象:', state2);
}
return {state1, state2, add1, add2}
}
}
</script>
ref
It is a copy of the original data and will not affect the original value. At the same time, the view will be updated synchronously after the value of the responsive data object changes.
The view has not changed, the original value has changed, and the value of the responsive data object has also changed, which means that it is a referencetoRef
to the original data , which will affect the original value, but the view will not be updated after the value of the responsive data object changes
ref
is a copy of the incoming data;toRef
is a reference to the incoming dataref
A change in the value of will update the view;toRef
a change in the value of will not update the view
toRefs
, its role is to convert the values of all attributes in the incoming object into responsive data objects. This function supports one parameter, that is, the obj
object
When passed obj
as a parameter to reactive
generate a responsive data object, if there obj
are more than one level, each level will be wrapped Proxy
once
shallowReactive
a shallow reactive
<template>
<p>{
{ state.a }}</p>
<p>{
{ state.first.b }}</p>
<p>{
{ state.first.second.c }}</p>
<button @click="change1">改变1</button>
<button @click="change2">改变2</button>
</template>
<script>
import {shallowReactive} from 'vue'
export default {
setup() {
const obj = {
a: 1,
first: {
b: 2,
second: {
c: 3
}
}
}
const state = shallowReactive(obj)
function change1() {
state.a = 7
}
function change2() {
state.first.b = 8
state.first.second.c = 9
console.log(state);
}
return {state}
}
}
</script>
Changed the second layer b
and the third layer c
, although the value has changed, but the view is not updated; when the first layer is changed a
, the entire view is updated; shallowReactive
the value of the first layer attribute is monitored, once it happens changed, update the view
shallowRef
A shallow one ref
, the shallowReactive
same as the one used for performance optimization
shallowReactive
It is the data change of the first layer of the monitoring object used to drive the view update, then shallowRef
it is .value
the change of the monitored value to update the view
<template>
<p>{
{ state.a }}</p>
<p>{
{ state.first.b }}</p>
<p>{
{ state.first.second.c }}</p>
<button @click="change1">改变1</button>
<button @click="change2">改变2</button>
</template>
<script>
import {shallowRef} from 'vue'
export default {
setup() {
const obj = {
a: 1,
first: {
b: 2,
second: {
c: 3
}
}
}
const state = shallowRef(obj)
console.log(state);
function change1() {
// 直接将state.value重新赋值
state.value = {
a: 7,
first: {
b: 8,
second: {
c: 9
}
}
}
}
function change2() {
state.value.first.b = 8
state.value.first.second.c = 9
console.log(state);
}
return {state, change1, change2}
}
}
</script>
triggerRef
, call it to update the view immediately, and it receives a parameter , which is the object state
to be updated ref
<template>
<p>{
{ state.a }}</p>
<p>{
{ state.first.b }}</p>
<p>{
{ state.first.second.c }}</p>
<button @click="change">改变</button>
</template>
<script>
import {shallowRef, triggerRef} from 'vue'
export default {
setup() {
const obj = {
a: 1,
first: {
b: 2,
second: {
c: 3
}
}
}
const state = shallowRef(obj)
console.log(state);
function change() {
state.value.first.b = 8
state.value.first.second.c = 9
// 修改值后立即驱动视图更新
triggerRef(state)
console.log(state);
}
return {state, change}
}
}
</script>
toRaw
method is used to get ref
or reactive
object's raw data
<template>
<p>{
{ state.name }}</p>
<p>{
{ state.age }}</p>
<button @click="change">改变</button>
</template>
<script>
import {reactive} from 'vue'
export default {
setup() {
const obj = {
name: 'xxx',
age: 22
}
const state = reactive(obj)
function change() {
state.age = 90
console.log(obj); // 打印原始数据obj
console.log(state); // 打印 reactive对象
}
return {state, change}
}
}
</script>
toRaw
The method reactive
gets the original data from the object
It is very convenient to do some performance optimization by modifying the value of the original data without updating the view
<script>
import {reactive, toRaw} from 'vue'
export default {
setup() {
const obj = {
name: 'xxx',
age: 22
}
const state = reactive(obj)
const raw = toRaw(state)
console.log(obj === raw) // true
}
}
</script>
markRaw
The method can mark the original data as non-responsive, even if it is used ref
or reactive
packaged, it still cannot achieve data responsiveness. It receives a parameter, that is, the original data, and returns the marked data
<template>
<p>{
{ state.name }}</p>
<p>{
{ state.age }}</p>
<button @click="change">改变</button>
</template>
<script>
import {reactive, markRaw} from 'vue'
export default {
setup() {
const obj = {
name: 'xxx',
age: 22
}
// 通过markRaw标记原始数据obj, 使其数据更新不再被追踪
const raw = markRaw(obj)
// 试图用reactive包装raw, 使其变成响应式数据
const state = reactive(raw)
function change() {
state.age = 90
console.log(state);
}
return {state, change}
}
}
</script>
markRaw
Whether the data processed by the method can be reactive
packaged into responsive data
watch
Both watchEffect
are used to monitor a data change to perform a specified operation
<script>
import {ref, watch} from 'vue'
export default {
setup() {
const state = ref(0)
watch(state, (newValue, oldValue) => {
console.log(`原值为${oldValue}`)
console.log(`新值为${newValue}`)
/* 1秒后打印结果:
原值为0
新值为1
*/
})
// 1秒后将state值+1
setTimeout(() => {
state.value ++
}, 1000)
}
}
</script>
<script>
import {reactive, watch} from 'vue'
export default {
setup() {
const state = reactive({count: 0})
watch(() => state.count, (newValue, oldValue) => {
console.log(`原值为${oldValue}`)
console.log(`新值为${newValue}`)
/* 1秒后打印结果:
原值为0
新值为1
*/
})
// 1秒后将state.count的值+1
setTimeout(() => {
state.count ++
}, 1000)
}
}
</script>
<script>
import {reactive, watch} from 'vue'
export default {
setup() {
const state = reactive({ count: 0, name: 'xx' })
watch(
[() => state.count, () => state.name],
([newCount, newName], [oldvCount, oldvName]) => {
console.log(oldvCount) // 旧的 count 值
console.log(newCount) // 新的 count 值
console.log(oldName) // 旧的 name 值
console.log(newvName) // 新的 name 值
}
)
setTimeout(() => {
state.count ++
state.name = 'dd'
}, 1000)
}
}
</script>
The watch method will return a stop method. If you want to stop monitoring, you can directly execute the stop function
watchEffect
No need to manually import dependencies
A callback function will be executed every time it is initialized to automatically obtain dependencies
The original value cannot be obtained, only the changed value can be obtained
<script>
import {reactive, watchEffect} from 'vue'
export default {
setup() {
const state = reactive({ count: 0, name: 'xx' })
watchEffect(() => {
console.log(state.count)
console.log(state.name)
/* 初始化时打印:
0
xx
1秒后打印:
1
da
*/
})
setTimeout(() => {
state.count ++
state.name = 'da'
}, 1000)
}
}
</script>
const store = useStore()
Vue3 getCurrentInstance().ctx
<template>
<div>
<div ref="el">div元素</div>
</div>
</template>
<script>
import { ref, onMounted } from 'vue'
export default {
setup() {
// 创建一个DOM引用,名称必须与元素的ref属性名相同
const el = ref(null)
// 在挂载后才能通过 el 获取到目标元素
onMounted(() => {
el.value.innerHTML = '内容被修改'
})
// 把创建的引用 return 出去
return {el}
}
}
</script>
Add the group to contact the author vx: xiaoda0423
Warehouse address: https://github.com/webVueBlog/WebGuideInterview