目录

选项式API和组合式API

选项式API

组合式API

语法糖

选项式API和组合式API的关系

生命周期函数

组合式API的生命周期函数

选项式API的生命周期函数

组件的注册和引用

注册组件

全局注册

局部注册

引用组件

解决组件之间的样式冲突

scoped属性

深度选择器

父组件向子组件传递数据

声明props

静态绑定props

动态绑定props

字符串类型数据

数字类型数据

布尔值类型数据

数组类型数据

对象类型数据

props 单项数据流

验证props

基础类型检查

必填项的校验

属性默认值

自定义验证函数

子组件向父组件传递数据

在子组件中声明自定义事件

在子组件中触发自定义事件

在父组件中监听自定义事件

跨级组件之间的数据传递

provide()

inject()函数

动态组件

定义动态组件

利用KeepAlive组件实现组件缓存

组件缓存相关的生命周期函数

KeepAlive组件的常用属性

插槽

定义插槽

使用插槽

具名插槽

作用域插槽

定义数据

接收数据

自定义指令

引用静态资源

引用public目录中的静态资源

引用src\assets目录中的静态资源


选项式API和组合式API

选项式API

选项式API是一种通过包含多个选项的对象来描述组件逻辑的API,其常用的选项包括data、method、computed、watch等。

export default {// 数据选项data() {return {//定义数据}},// 计算属性computed: {},// 方法methods: {},// 生命周期钩子created() {},mounted() {},// 侦听器watch: {}
}

组合式API

组合式API是将组件中的数据、方法、计算属性、侦听器等代码全部组合在一起,写在setup函数中。

<script>
import { computed, watch } from 'vue'export default {setup() {const 数据名 = 数据值 // 这里应该是定义一个响应式数据,原代码不完整,假设为某个响应式数据const 方法名 = () => {} // 这里应该是定义一个方法const 计算属性名 = computed(() => {}) // 定义计算属性watch(侦听器的来源, 回调函数, 可选参数) // 定义侦听器,原代码中参数未具体化return { 数据名, 方法名, 计算属性名 }}
}
</script>

语法糖

用于简化组合式API的代码。

<script setup>
import { computed, watch } from 'vue'// 定义数据(这里假设使用 ref 或 reactive 来定义响应式数据,原代码未具体化,以下以 ref 为例)
import { ref } from 'vue';
const 数据名 = ref(数据值); // 实际使用时需将“数据值”替换为具体的初始值// 定义方法
const 方法名 = () => {// 方法的具体逻辑
};// 定义计算属性
const 计算属性名 = computed(() => {// 计算属性的具体逻辑,返回计算后的值
});// 定义侦听器
watch(() => 侦听器的来源, // 这里需要明确侦听的具体响应式数据或计算属性等(newValue, oldValue) => {// 回调函数,当侦听的来源发生变化时执行// 可以使用 newValue 和 oldValue 进行相应操作},{// 可选参数,例如 deep、immediate 等}
);
</script>

选项式API和组合式API的关系

选项式API和组合式API是同一底层系统提供的两套不同的接口。

选项式API是在组合式API的基础上实现的。

如果使用选项式API,整个项目逻辑不易阅读和理解,而且查找对应功能的代码会存在一定难度。

如果使用组合式API,可以将项目的每个功能的数据、方法放到一起,这样不管项目的大小,都可以快速定位到功能区域的相关代码,便于阅读和维护。同时,组合式API可以通过函数来实现高效的逻辑复用,这种形式更加自由,需要开发者有较强的代码组织能力和拆分逻辑能力。

生命周期函数

在Vue中,组件的生命周期是指每个组件从被创建到被销毁的整个过程,每个组件都有生命周期。如果想要在某个特定的时期进行特定的处理,可以通过生命周期函数来完成。随着组件生命周期的变化,生命周期函数会自动执行。

组合式API的生命周期函数

函数说明
onBeforeMount()组件挂载前
onMounted()

组件挂载成功后

onBeforeUpdate()

组件更新前

onUpdated()组件中的任意DOM元素更新后
onBeforeUnmount()组件实例被销毁前
onUnmounted()组价实例被销毁后

<script setup>
import { ref, onBeforeMount, reactive } from 'vue'
const loading=ref(true)
const items = reactive([])
onBeforeMount(async ()=>{try{const res = await fetch('/data/data.json')if(res.ok){const data = await res.json();data.forEach(item => {items.push(item)});}else{console.log('数据获取错误',res.status)}}catch(err){console.log("数据获取错误",err)}finally{loading.value=false}}
)
</script>

选项式API的生命周期函数

函数说明
beforeCreate()实例对象创建前
created()实例对象创建后
beforeMount()页面挂载前
mounted()页面挂载成功后
beforeUpdate()组价更新前
updated()组件中任意的DOM元素更新后
beforeDestory()组件实例销毁前
destroyed()组件实例销毁后

组件的注册和引用

当在Vue项目中定义了一个新的组件后,要想在其他组件中引用这个新的组件,需要对新的组件进行注册。在注册组件的时候,需要给组件取一个名字,从而区分每个组件,可以采用帕斯卡命名法为组件命名。

Vue提供了两种注册组件的方式,分别是全局注册和局部注册。

注册组件

全局注册

在实际开发中,如果某个组件的使用频率很高,许多组件中都会引用该组件,则推荐将该组件全局注册。被全局注册的组件可以在当前Vue项目的任何一个组件内引用。

import { createApp } from 'vue';
import './style.css';
import App from './App.vue';
import MyComponent from './components/MyComponent.vue';const app = createApp(App);
app.component('MyComponent', MyComponent);
app.mount('#app');

component()支持链式调用,可以连续注册多个组件。

局部注册

在实际开发中,如果某些组织只在特定的情况下被用到,推荐进行局部注册。局部注册即在某个组件中注册,被注册的主键只能在当前注册范围内使用。

<script>
import ComponentA from './ComponentA.vue'
export default {components: { ComponentA }
}
</script>

在使用setup语法糖时,导入的组件会被自动注册,无须手动注册,导入后可以直接在模版中使用。

<script setup>
import ComponentA from './ComponentA.vue'
</script>

引用组件

将组件注册完成后,若要将组件在页面中渲染出俩,需要引用组件。

在组件的<template>标签中可以引用其他组件,被引用的组件需要写成标签的形式,标签名应与组件名对应。组件的标签名可以使用短横线分隔或帕斯卡命名法命名。

例如,<my-component>标签和<MyComponent>标签都表示引用MyComponent组件。一个组件可以被引用多次,但不可出现自我引用和互相引用的情况,否则会出现死循环。

解决组件之间的样式冲突

在Vue中可以使用scoped属性和深度选择器来解决组件之间样式的冲突。

scoped属性

<style>标签添加scoped属性后,Vue会自动为当前组件的DOM元素添加一个唯一的自定义属性,并在样式中为选择器添加自定义属性,从而限制样式的作用范围,防止组件之间的样式冲突问题。

深度选择器

如果在添加了scoped属性后还需要让某些样式对子组件生效,则可以使用深度选择器来实现。

深度选择器通过:deep()伪类来实现,在其小括号中可以定义用于子组件的选择器。

父组件向子组件传递数据

声明props

在不使用setup语法糖的情况下,可以使用props选项声明props。

props选项的形式可以是对象或字符串数组。

<script>
export default {props: {message: String,isVisible: Boolean}
}
</script>

如果不需要限制props的类型,可以声明字符串数组形式的props。

<script>
export default {props: [message,isVisible]
}
</script>

使用setup语法糖时,可使用defineProps()函数声明props。

<script setup>
const props = defineProps({title: String,count: Number
})
</script>
<script setup>
const props = defineProps(['title', 'count'])
</script>

在组件中声明了props后,可以直接在模版中输出每个prop的值。

静态绑定props

当在父组件中引用了子组件后,如果子组件中声明了props,则可以在父组件中向子组件传递数据。如果传递的数据是固定不变的,则可以通过静态绑定props的方式为子组件传递数据。

通过静态绑定props的方式为子组件传递数据。

<子组件标签名 自定义属性A=“数据” 自定义属性B=“数据” />

父组件向子组件的props传递了静态的数据,属性值默认为字符串类型。

动态绑定props

在父组件中使用v-bind可以为子组件动态绑定props,任意类型的值都可以传给子组件的props,包括字符串、数字、布尔值、数组、对象等。

字符串类型数据
<template><Child :init="username" />
</template><script setup>
import Child from './Child.vue'
import { ref } from 'vue'
const username = ref('小圆')
</script>
<template></template><script setup>
const props = defineProps(['init'])
console.log(props)
</script>

数字类型数据
<template><Child :init="12" /><Child :init="age" />
</template><script setup>
import Child from './Child.vue'
import { ref } from 'vue'
const age = ref(12)
</script>

布尔值类型数据
<template><Child init /><Child :init="false" /><Child :init="isFlag" />
</template><script setup>
import Child from './Child.vue'
import { ref } from 'vue'
const isFlag = ref(true)
</script>

数组类型数据
<template><Child :init="['唱歌', '跳舞', '滑冰']" /><Child :init="hobby" />
</template><script setup>
import Child from './Child.vue'
import { ref } from 'vue'
const hobby = ref(['唱歌', '跳舞', '滑冰'])
</script>

对象类型数据
<template><Child :init="{ height: '180厘米', weight: '70千克' }" /><Child :height="bodyInfo.height" :weight="bodyInfo.weight" /><Child v-bind="bodyInfo" />
</template>
<script setup>
import Child from './Child.vue'
import { reactive } from 'vue'
const bodyInfo = reactive({height: '180厘米',weight: '70千克'
})
</script>

props 单项数据流

在Vue中,所有的props都遵循单向数据流原则,props数据因父组件的更新而变化,变化后的数据将向下流往子组件,而且不会逆向传递,这样可以防止因子组件意外变更props导致数据流向难以理解的问题。

每次父组件绑定的props发生变更时,子组件中的props都将会刷新为最新的值。

验证props

使用字符串数组形式的props的缺点是无法为每个prop指定具体的数据类型,而使用对象形式的props的优点是可以对每个prop进行数据类型的校验。

对象形式的props可以使用多种验证方案,包括基础类型检查、必填项的校验、属性默认值、自定义验证函数等。在声明props时,可以添加验证方案。

基础类型检查

在开发中,有时需要对从父组件中传递过来的props数据进行基础类型检查,这时可以通过type属性检查合法的类型,如果从父组件中传递过来的值不符合此类型,则会报错。

常见的类型有String(字符串)、Number(数字)、Boolean(布尔值)、Array(数组)、Object(对象)、Date(日期)、Function(函数)、Symbol(符号)以及任何自定义构造函数。

const props = {// 自定义属性A,类型为字符串自定义属性A: String, // 自定义属性B,类型为数字自定义属性B: Number, // 自定义属性C,类型为布尔值自定义属性C: Boolean, // 自定义属性D,类型为数组自定义属性D: Array, // 自定义属性E,类型为对象自定义属性E: Object, // 自定义属性F,类型为日期自定义属性F: Date, // 自定义属性G,类型为函数自定义属性G: Function, // 自定义属性H,类型为符号自定义属性H: Symbol 
};
必填项的校验

父组件向子组件传递props数据时,有可能传递的数据为空,但是在子组件中要求该数据是必须传递的。此时,可以在声明props时通过required属性设置必填项,强调组件的使用者必须传递属性的值。

props: {自定义属性: { required: true },
}
属性默认值

在声明props时,可以通过default属性定义属性默认值,当父组件没有向子组件的属性传递数据时,属性将会使用默认值

props: {自定义属性: { default: 0 },
}
自定义验证函数

如果需要对从父组件中传入的数据进行验证,可以通过 validator() 函数来实现。validator() 函数可以将 prop 的值作为唯一参数传入自定义验证函数,如果验证失败,则会在控制台中发出警告。

props: {自定义属性: {validator(value) {return ['success', 'warning', 'danger'].indexOf(value)!== -1;},},
}

子组件向父组件传递数据

在子组件中声明自定义事件

若想使用自定义事件,首先需要在子组件中声明自定义事件。

在不使用 setup 语法糖时,可以通过 emits 选项声明自定义事件。

<script>
export default {emits: ['demo']
}
</script>

在使用 setup 语法糖时,需要通过调用 defineEmits() 函数声明自定义事件。

<script setup>
const emit = defineEmits(['demo'])
</script>

在子组件中触发自定义事件

在子组件中声明自定义事件后,接着需要在子组件中触发自定义事件。

当使用场景简单时,可以使用内联事件处理器,通过调用 $emit() 方法触发自定义事件,将数据传递给使用的组件。

<button @click="$emit('demo', 1)">按钮</button>

$emit() 方法的第 1 个参数为字符串类型的自定义事件的名称,第 2 个参数为需要传递的数据,当触发当前组件的事件时,该数据会传递给父组件。

除了使用内联方式外,还可以直接定义方法来触发自定义事件。

在不使用 setup 语法糖时,可以从 setup() 函数的第 2 个参数(即 setup 上下文对象)来访问到 emit() 方法。

export default {setup(props, ctx) {const update = () => {ctx.emit('demo', 2)}return { update }}
}

如果使用setup语法糖,可以调用emit()函数来实现。

<script setup>
const update = () => {emit('demo', 2)
}
</script>

在父组件中监听自定义事件

在父组件中通过 v-on 可以监听子组件中抛出的事件。

<子组件名 @demo="fun" />

当触发 demo 事件时,会接收到从子组件中传递的参数,同时会执行 fun() 方法。父组件可以通过 value 属性接收从子组件中传递来的参数。

const fun = value => {console.log(value)
}

跨级组件之间的数据传递

Vue提供了跨级组件之间数据传递的方式——依赖注入。一个父组件相对于其所有的后代组件而言,可作为依赖提供者。而任何后代的组件树,无论层级多深,都可以注入由父组件提供的依赖。

对于父组件而言,如果要为后代组件提供数据,需要使用provide()函数。对于子组件而言,如果想要注入上层组件或整个应用提供的数据,需要使用inject()函数。

provide()

provide()函数可以提供一个值,用于被后代组件注入。

provide(注入名, 注入值)

provide()函数可以接收2个参数,第1个参数是注入名,后代组件会通过注入名查找所需的注入值;第2个参数是注入值,值可以是任意类型,包括响应式数据。

在不使用 setup 语法糖的情况下,provide()函数必须在组件的 setup()函数中调用。

<script>
import { ref, provide } from 'vue'
export default {setup() {const count = ref(1)provide( 'message', count )}
}
</script>

当使用 setup 语法糖时,使用 provide()函数。

<script setup>
import { provide } from 'vue'
provide('message', 'Hello Vue.js')
</script>

provide()函数除了可以在某个组件中提供依赖外,还可以全局提供依赖。

const app = createApp(App)
app.provide('message', 'Hello Vue.js')

inject()函数

inject()函数可以注入上层组件或者整个应用提供的数据。inject()函数的语法格式。

inject(注入值,默认值,布尔值)

第1个参数是注入值,Vue会遍历父组件,通过匹配注入的值来确定所提供的值,如果父组件链上多个组件为同一个数据提供了值,那么距离更近的组件将会覆盖更远的组件所提供的值。

第2个参数是可选的,用于在没有匹配到注入的值时使用默认值。第2个参数可以是工厂函数,用于返回某些创建起来比较复杂的值。如果提供的默认值是函数,还需要将false作为第3个参数传入,表明这个函数就是默认值,而不是工厂函数。

第3个参数是可选的,类型为布尔值,当参数值为false时,表示默认值是函数;当参数值为true时,表示默认值为工厂函数;当省略参数值时,表示默认值为其他类型的数据,不是函数或工厂函数。

动态组件

定义动态组件

利用动态组件可以动态切换页面中显示的组件。

<component is="要渲染的组价"></component>

标签必须配合is属性一起使用,is属性的属性值表示要渲染的组件,当该属性值发生变化时,页面中渲染的组件也会发生变化。

is属性的属性值可以是字符串或组件,当属性值为组件时,如果要实现组件的切换,需要调用shallowRef()函数定义响应式数据,将组件保存为响应式数据。shallowRef()函数只处理对象最外层属性的响应,它比ref()函数更适合于将组件保存为响应式数据。

利用KeepAlive组件实现组件缓存

组件缓存可以使组件创建一次后,不会被销毁。在Vue中可以通过KeepAlive组件来实现组件缓存。

KeepAlive组件可通过标签来定义,定义时使用标签包裹需要被缓存的组件。

<KeepAlive>被缓存的组件
</KeepAlive>

组件缓存相关的生命周期函数

当组件被激活时,会触发组件的onActivated()生命周期函数;当组件被缓存时,会触发组件的onDeactivated()生命周期函数。

// onActivated()生命周期函数
onActivated(() => { })
// onDeactivated()生命周期函数
onDeactivated(() => { })

KeepAlive组件的常用属性

在默认情况下,所有被标签包裹的组件都会被缓存。如果想要实现特定组件被缓存或者特定组件不被缓存的效果,可以通过KeepAlive组件的常用属性include、exclude属性来实现。

属性类型说明
include字符串或正则表达式只有名称匹配的组件会被缓存
exclude字符串或正则表达式名称匹配的组件不会被缓存
max数字最多可以缓存组件实例个数

在标签中使用include属性和exclude属性时,多个组件名之间使用英文逗号分隔。

<KeepAlive include="组件名1, 组件名2">被缓存的组件
</KeepAlive>

注意:

在使用KeepAlive组件对名称匹配的组件进行缓存时,它会根据组件的name选项进行匹配。如果没有使用setup语法糖,必须手动声明name选项;如果使用了setup语法糖,Vue会根据文件名自动生成name选项,无须手动声明name选项。例如,在MyLeft.vue文件中使用setup语法糖时,自动生成的组件名为MyLeft。

插槽

Vue为组件的封装者提供了插槽(slot),插槽是指开发者在封装组件时不确定的、希望由组件的使用者指定的部分。也就是说,插槽是组件封装期间为组件的使用者预留的占位符,允许组件的使用者在组件内展示特定的内容。通过插槽,可以使组件更灵活、更具有可复用性。

定义插槽

在封装组件时,可以通过标签定义插槽,从而在组件中预留占位符。假设项目中有一个MyButton组件。

<template><button><slot></slot></button>
</template>

在标签内可以添加一些内容作为插槽的默认内容。如果组件的使用者没有为插槽提供任何内容,则默认内容生效;如果组件的使用者为插槽提供了插槽内容,则该插槽内容会取代默认内容。

另外,如果一个组件没有预留任何插槽,则组件的使用者提供的任何插槽内容都会不起作用。

使用插槽

使用插槽即在父组件中使用子组件的插槽,在使用时需要将子组件写成双标签的形式,在双标签内提供插槽内容。

<template><MyButton>按钮</MyButton>
</template>

因为插槽内容是在父组件模板中定义的,所以在插槽内容中可以访问到父组件的数据。插槽内容可以是任意合法的模板内容,不局限于文本。

<MyButton><span style="color: yellow;">按钮</span><MyLeft />
</MyButton>

具名插槽

在Vue中当需要定义多个插槽时,可以通过具名插槽来区分不同的插槽。具名插槽是给每一个插槽定义一个名称,这样就可以在对应名称的插槽中提供对应的数据了。

插槽通过标签来定义,标签有一个name属性,用于给各个插槽分配唯一的名称,以确定每一处要渲染的内容。添加name属性的标签可用来定义具名插槽。

<slot name="插槽名称"></slot>

在父组件中,如果要把内容填充到指定名称的插槽中,可以通过一个包含v-slot指令的<template>来实现。

<组件名><template v-slot:插槽名称></template>
</组件名>

与v-on和v-bind类似,v-slot也有简写形式,即吧v-slot替换为#。

作用域插槽

一般情况下,在父组件中不能使用子组件中定义的数据。如果想要在父组件中使用子组件中定义的数据,则需要通过作用域插槽来实现。

作用域插槽是带有数据的插槽,子组件提供一部分数据给插槽,父组件接收子组件的数据进行页面渲染。

定义数据

在封装组件的过程中,可以为预留的插槽定义数据,供父组件接收并使用子组件中的数据。在作用域插槽中,可以将数据以类似传递props属性的形式添加到标签上。

<slot message="Hello Vue.js"></slot>

接收数据

使用默认插槽和具名插槽接收数据的方式不同,接下来分别进行讲解。

在Vue中,每个插槽都有name属性,表示插槽的名称。在定义插槽时虽然省略了标签的name属性,但是name属性默认为default,这样的插槽属于默认插槽。

在父组件中可以通过v-slot指令接收插槽中定义的数据,即接收作用域插槽对外提供的数据。通过v-slot指令接收到的数据可以在插槽内通过Mustache语法进行访问。

<MyHeader v-slot="scope"><p>{{ scope.message }}</p>
</MyHeader>

通过v-slot接收从作用域插槽中传递的数据,scope为形参,表示从作用域插槽中接收的数据,该形参的名称可以自定义。

作用域插槽对外提供的数据对象可以使用解构赋值以简化数据的接收过程。

<MyHeader v-slot="{ message }"><p>{{ message }}</p>
</MyHeader>

通过解构赋值解构对象,解构后子组件中定义的数据可以直接访问,而不是以“形参.属性”的方式访问。

自定义指令

Vue中的自定义指令分为两类,分别是私有自定义指令和全局自定义指令。

  • 私有自定义指令是指在组件内部定义的指令。私有自定义指令可以在定义该指令的组件内部使用。例如,在组件A中自定义了指令,只能在组件A中使用,组件B、组件C中不能使用。

  • 全局自定义指令是指在全局定义的指令。全局自定义指令可以在全局使用,例如,在src\main.js文件中定义了全局自定义指令,这个指令可以用于任何一个组件。

一个自定义指令由一个包含自定义指令生命周期函数的参数来定义。

函数名说明
created()在绑定元素的属性前调用
beforeMount()在绑定元素被挂载前调用
mounted()在绑定元素的父组件及自身的所有子节点都挂载完成后调用
beforeUpdate()在绑定元素的父组件更新前调用
updated()在绑定元素的父组件及自身的所有子节点都更新后调用
beforeUnmount()在绑定元素的父组件卸载前调用
unmounted()在绑定元素的父组件卸载后调用
el指令所绑定的元素,可以直接用于操作DOM元素
binding一个对象,包含很多属性,用于接收属性的参数值
vnode代表绑定元素底层的虚拟节点
prevNode之前页面渲染中指令所绑定元素的虚拟节点

binding中包含以下6个常用属性。

  • value:传递给指令的值。
  • arg:传递给指令的参数。
  • oldValue:之前的值,仅在beforeUpdate()函数和updated()函数中可用,无论值是否更改都可用。
  • modifiers:一个包含修饰符的对象 (如果有)。例如,在v-my-directive.foo.bar 中,修饰符对象是{ foo: true, bar: true }。
  • instance:使用该指令的组件实例。
  • dir:指令的定义对象。

如果没有使用setup语法糖,可以在directives属性中声明私有自定义指令。

export default {directives: {color: {}}
}

在使用自定义指令时,需要以“v-”开头。

<h1 v-color>标题</h1>

如果使用setup语法糖,任何以“v”开头的驼峰式命名的变量都可以被用作一个自定义指令。

<template><span v-color></span>
</template><script setup>
const vColor = {}
</script>

全局自定义指令需要通过Vue应用实例的directive()方法进行声明。

directive('自定义指令名称', 对象)

directive()方法的第1个参数类型为字符串,表示全局自定义指令的名称;第2个参数类型为对象或者函数,可以是对象或者函数形式,用于接收指令的参数值。

在使用自定义指令时,开发人员可以通过自定义指令的参数改变元素的状态,传递的参数由自定义指令的生命周期函数的第2个参数接收。

在标签中使用自定义指令时,通过等号(=)的方式可以为当前指令绑定参数.

<h1 v-color="color"></h1>

如果指令需要多个值,可以传递一个对象。

<div v-demo="{ color: 'red', text: 'hello' }"></div>

对于自定义指令来说,通常仅需要在mounted()函数和updated()函数中操作DOM元素,除此之外,不需要其他的生命周期函数。

将私有自定义指令简写为函数形式。

const vFontSize = (el, binding) => {el.style.fontSize = binding.value
}

将全局自定义指令简写成函数形式。

app.directive('fontSize', (el, binding) => {el.style.fontSize = binding.value
})

引用静态资源

组件中,有时需要引用一些静态资源,例如图片资源、CSS代码资源等。通过项目的public目录和src\assets目录都可以存放静态资源,但引用静态资源的方式不同。

引用public目录中的静态资源

public目录用于存放不可编译的静态资源文件,该目录下的文件会被复制到打包目录,该目录下的文件需要使用绝对路径访问。

<img src="/demo.png" >

引用src\assets目录中的静态资源

src\assets目录用于存放可编译的静态资源文件,例如图片、样式文件等。该目录下的文件需要使用相对路径访问。

在引用src\assets目录中的图片时,首先将图片保存到本地,然后使用import语法将图片导入需要的组件,最后通过img元素的src属性添加图片的路径。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/87369.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/87369.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/87369.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Yii2 安装-yii2-imagine

#composer 安装-如已安装跳过 php -r "copy(https://install.phpcomposer.com/installer, composer-setup.php);" php composer-setup.php sudo mv composer.phar /usr/local/bin/composer#执行安装 composer require --prefer-dist yiisoft/yii2-imagine#报错 Updat…

C#程序设计简介

一、发展历史 C#的主要作者是丹麦计算机科学家安德斯海尔斯伯格&#xff08;Anders Hejlsberg&#xff09;&#xff0c;他是该语言的首席设计师&#xff0c;同时也是Turbo Pascal&#xff08;Pascal 语言编译器&#xff09;、Delphi&#xff08;由 Borland&#xff08;后被 Em…

JavaWeb笔记03

七、Maven1_概述Maven 是专门用于管理和构建 Java 项目的工具&#xff0c;它的主要功能有: 提供了一套标准化的项目结构 提供了一套标准化的构建流程&#xff08;编译&#xff0c;测试&#xff0c;打包&#xff0c;发布……&#xff09; 提供了一套依赖管理机制1.标准化的项目结…

AIGC自我介绍笔记

AIGC&#xff08;人工智能生成内容&#xff09;项目是指利用人工智能技术&#xff08;如深度学习、生成对抗网络、大规模预训练模型等&#xff09;自动生成文本、图像、音频、视频等多模态内容的系统性工程。这类项目通过算法模型学习海量数据&#xff0c;实现内容的自动化、个…

从docker-compose快速入门Docker

不得不提容器化技术是未来的一个发展方向&#xff0c;它彻底释放了计算虚拟化的威力&#xff0c;极大提高了应用的运行效率&#xff0c;降低了云计算资源供应的成本&#xff01;使用 Docker&#xff0c;可以让应用的部署、测试和分发都变得前所未有的高效和轻松&#xff01;无论…

【BERT_Pretrain】Wikipedia_Bookcorpus数据预处理(二)

上一篇介绍了wikipedia和bookcopus数据集&#xff0c;这一篇主要讲一下如何预处理数据&#xff0c;使其可以用于BERT的Pretrain任务MLM和NSP。 MLM是类似于完形填空的任务&#xff0c;NSP是判断两个句子是否连着。因此数据预处理的方式不同。首先&#xff0c;拿到原始数据集&a…

人工智能-基础篇-14-知识库和知识图谱介绍(知识库是基石、知识图谱是增强语义理解的知识库、结构化数据和非结构化数据区分)

在人工智能&#xff08;AI&#xff09;领域&#xff0c;知识图谱&#xff08;Knowledge Graph&#xff09;和知识库&#xff08;Knowledge Base&#xff09;是两种重要的知识表示和管理技术&#xff0c;它们的核心目标是通过结构化的方式组织信息&#xff0c;从而支持智能系统的…

7月1日作业

思维导图 一、将当前的时间写入到time.txt的文件中&#xff0c;如果ctrlc退出之后&#xff0c;在再次执行支持断点续写 1.2022-04-26 19:10:20 2.2022-04-26 19:10:21 3.2022-04-26 19:10:22 //按下ctrlc停止&#xff0c;再次执行程序 4.2022-04-26 20:00:00 5.2022-04-26 20:0…

DHCP中继及动态分配

DHCP中继 在多 VLAN 网络中为什么不能直接用 DHCP&#xff1f; 比如你现在的网络是&#xff1a;PC 在 VLAN10、VLAN20 中DHCP服务器&#xff08;Router0&#xff09;在另一个网段&#xff08;比如 192.168.100.0/24&#xff09;PC 的 DHCP Discover 是广播&#xff0c;无法跨越…

ROS 概述与环境搭建

1. ROS 简介 1.1 ROS 诞生背景 机器人是一种高度复杂的系统性实现&#xff0c;机器人设计包含了机械加工、机械结构设计、硬件设计、嵌入式软件设计、上层软件设计....是各种硬件与软件集成&#xff0c;甚至可以说机器人系统是当今工业体系的集大成者。 机器人体系是相当庞大的…

mac python3.13 selenium安装使用

一、安装 # 进入虚拟环境 workon xxxx pip install selenium二、安装驱动 查询自己浏览器版本 /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --versionGoogle Chrome 138.0.7204.93下载对应的驱动&#xff0c;其他版本 sudo mv ~/Downloads/chromedr…

AI 开发平台:中小企业的创新破局点在哪里?

在浙江义乌的一个小商品加工厂里&#xff0c;老板王建国最近有点烦。订单量忽高忽低&#xff0c;原材料价格波动不定&#xff0c;他想通过数据分析提前规划生产&#xff0c;却苦于没有专业的技术团队&#xff1b;在广东东莞的一家电子配件公司&#xff0c;业务员李娜每天要处理…

.NET 8.0 Redis 教程

一、环境准备 1. 安装 Redis 服务器 Windows/macOS/Linux&#xff1a;使用 Docker 快速部署 bash docker run -d --name redis -p 6379:6379 redisLinux&#xff1a;直接安装 bash sudo apt-get install redis-server sudo systemctl start redis-server2. 创建 .NET 项目 b…

2025年游戏鼠标推荐,游戏鼠标推荐,打CSGO(罗技、雷蛇、卓威、ROG、漫步者、赛睿、达尔优)

可能很多人对于游戏鼠标的了解还是不够深&#xff0c;会有很多疑问&#xff0c;比如&#xff1a;“游戏鼠标和办公鼠标的区别”、“游戏鼠标无线好还是有线好”等等一系列的问题&#xff0c;本文将会介绍游戏鼠标领域处于领先地位的几个厂家&#xff1a;罗技鼠标、雷蛇鼠标、赛…

OpenCV CUDA模块设备层-----在 GPU上高效地执行两个uint类型值的最小值比较函数vmin2()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 OpenCV 的CUDA模块&#xff08;cudev&#xff09; 中的一个设备端内联函数&#xff0c;用于在GPU上高效地执行两个uint类型值的最小值比较。 该函…

Web3与传统网络安全模型对比:关键差异解析

随着互联网技术的飞速发展&#xff0c;Web3的概念逐渐成为人们关注的焦点。Web3代表着一个更加去中心化、安全和用户友好的网络环境。与传统的网络安全模型相比&#xff0c;Web3在多个方面展现出了其独特的优势和特点。本文将深入探讨Web3与传统网络安全模型之间的关键差异。 …

FLAN:微调语言模型是 Zero-Shot 学习者

摘要 本文探讨了一种简单的方法来提升语言模型的零样本学习能力。我们展示了指令微调——即在通过指令描述的数据集集合上对语言模型进行微调——能够显著提升模型在未见任务上的零样本表现。 我们以一个拥有1370亿参数的预训练语言模型为基础&#xff0c;在60多个通过自然语…

springboot中的事件发布和监听

事件定义 创建一个自定义事件类 UserLoginEvent&#xff0c;继承 ApplicationEvent&#xff0c;用于携带用户登录信息&#xff1a; import org.springframework.context.ApplicationEvent;public class UserLoginEvent extends ApplicationEvent { //关键点1&#xff1a;ext…

“开源双轨架构+40亿参数扩散Transformer——ComfyUI-OmniGen2本地部署教程:重塑多模态生成的效率边界!

一、简介 OmniGen2 是由北京智源研究院最新推出的一个强大、高效的开源多模态生成模型。与 OmniGen v1 不同&#xff0c;OmniGen2 具有两种不同的文本和图像模态解码路径&#xff0c;利用非共享参数和解耦的图像分词器。OmniGen2 在四个主要功能方面具有竞争力的性能&#xff…

Java的SpringAI+Deepseek大模型实战之会话记忆

文章目录 背景项目环境实现步骤第一步、定义会话存储方式方式一、定义记忆存储ChatMemory方式二、注入记忆存储ChatMemory 第二步、配置会话记忆方式一、老版本实现方式二、新版本实现 第三步、存储会话信息 异常处理1、InMemoryChatMemory 无法解析 背景 前两期【环境搭建】和…