目录
vue3已经出了好长一段时间了,最近闲来无事简单学习了一下,新增的东西还是挺多的,写一篇文章来记录一下。
谈到 vue3,首先想到的就是组合式api,很大程度的解决了vue2选项式api的缺点,那有啥缺点?当文件中的业务代码非常多的时候,阅读修改代码的时候是非常痛苦的,data,method,watch还有计算属性之间来回跳转, 我已经准备拔刀了。
下面这些图被疯转,很形象的展现了vue2和vue3的区别,可以看到组合式api就是将单个功能的状态,方法,计算属性等等需要用到的东西都组合在一起抽离成一个hook,也就是对应图4的function,最终再统一引入组合到一起。这样做的好处就是单个功能的代码都在一起,方便调式修改。
setup是vue3的一个新的配置项,只在初始化的时候执行一次,所有的组合式函数都在此使用。setup可以在选项式api的风格中使用也可以通过组合式api的风格 。通过代码简单对比一下。vue3推荐使用组合式。
<script>
import { ref } from 'vue'
export default {
setup() {
const sum = ref(1)
return {
sum,
}
},
}
</script>
<template>
<div>
<h1>v3</h1>
<h3>{
{ sum }}</h3>
<button @click="sum++">+1</button>
</div>
</template>
<style scoped></style>
<script setup>
import { ref } from 'vue'
const sum = ref(1)
</script>
<template>
<div>
<h1>v3</h1>
<h3>{
{ sum }}</h3>
<button @click="sum++">+1</button>
</div>
</template>
<style scoped></style>
<script setup>
中的导入和顶层变量/函数都能够在模板中直接使用, 选项式则需要导出<script setup>打包出来的体积更小
<script setup>对ts更友好
官网介绍的比较详细,感兴趣可以查看
组合式 API 常见问答 | Vue.js
vue2中 data 函数返回的对象就是响应式的数据,但是在增加删除对象属性时不是响应式的,当然vue2中也有对应的解决方法,this.$set(), this.$delete(), 其实这也能够理解,毕竟vue2的响应式式基于 Object.defineProperty 实现的,这个函数只提供了 get 和 set 以及一些描述符 descriptor,并没有提供 add 和 delete 方法。
vue3中的响应式包含了两种形态, ref(底层还是Object.defineProperty进行数据劫持, 处理简单数据类型),reactive(使用es6的Proxy进行数据劫持,处理复杂数据类型),完全修复了vue2响应式的痛点,vue3的响应式更加的友好。
ref 接受一个值,返回一个响应式对象,一般用来处理简单数据类型的响应式,但如果传入的值是对象 ref 会求助 reactive,返回RefImpl的实例简称ref对象。 此时可能会有疑惑,既然ref是一个响应式的对象,为什么模板中能正常解析。这是因为在解析templete时遇到ref对象会自动取其value属性,但是如果要在方法中修改ref创建的响应式数据,你的写法应该是这样的 state.value = xxx
<script setup>
import { ref } from 'vue'
const sum = ref(1)
function add() {
sum.value++
}
</script>
<template>
<div>
<h1>v3</h1>
<h3>{
{ sum }}</h3>
<button @click="add">+1</button>
</div>
</template>
<style scoped></style>
为对象做深层!!!!响应式代理, 也就是如果对象有多层依旧是响应式的,返回一个Proxy实例, 如果传入一个字符串或者数字,它将不是响应式的。Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)Proxy - JavaScript | MDN。Vue使用 Proxy 进行数据劫持, Reflect 进行反射修改 Reflect - JavaScript | MDN
<script setup>
import { reactive } from 'vue'
const person = reactive({
name: '张三',
age: 12,
job: {
j1: {
jname: '前端开发',
},
},
})
function add() {
person.hobby = ['唱', '跳', 'rap']
}
function deleteHB() {
delete person.hobby
}
</script>
<template>
<div>
<h1>v3</h1>
<h1>{
{ sum }}</h1>
<h3>姓名:{
{ person.name }}</h3>
<h3>年龄:{
{ person.age }}</h3>
<h3>工作:{
{ person.job.j1.jname }}</h3>
<h3 v-if="person.hobby">爱好: {
{ person.hobby }}</h3>
<button @click="person.name += '-'">修改姓名</button>
<button @click="person.age++">修改年龄</button>
<button @click="person.job.j1.jname += '!'">修改工作</button>
<button @click="add">增加爱好</button>
<button @click="deleteHB">删除爱好</button>
</div>
</template>
<style scoped></style>
shallowRef 直译过来意思是浅层的 ref,shallowRef 传入对象不会求助 reactive,仅仅对ref对象的 value 属性具有响应式。
shallowReactive 只处理对象第一层的响应式, 如果修改了深层的数据页面是不会响应的,但是会在下次页面更新中渲染出来。
<script setup>
import { shallowReactive, shallowRef, ref, reactive } from 'vue'
const shallowRef_jack = shallowRef({ name: 'jack', sex: '女' })
const shallowReactive_ben = shallowReactive({
name: 'ben',
sex: '女',
child: {
son: {
name: '张三',
},
},
})
const ref_jack = ref({ name: 'jack', sex: '女' })
const reactive_ben = reactive({
name: 'ben',
sex: '女',
child: {
son: {
name: '张三',
},
},
})
</script>
<template>
<div>
<h1>v3</h1>
<h3>
shallowRef_jack: {
{ shallowRef_jack }}
<button @click="shallowRef_jack = {}">修改整个对象</button>
<button @click="shallowRef_jack.name += '!'">修改对象属性</button>
</h3>
<h3>
ref_jack: {
{ ref_jack }}
<button @click="ref_jack = {}">修改整个对象</button>
<button @click="ref_jack.name += '!'">修改对象属性</button>
</h3>
<h3>
shallowReactive_ben: {
{ shallowReactive_ben }}
<button @click="shallowReactive_ben.child.son.name = '!'">
修改对象的第三层属性
</button>
<button @click="shallowReactive_ben.name += '!'">
修改对象第一层属性
</button>
</h3>
<h3>
reactive_ben: {
{ reactive_ben }}
<button @click="reactive_ben.child.son.name += '!'">
修改对象的第三层属性
</button>
<button @click="reactive_ben.name += '!'">修改对象第一层属性</button>
</h3>
</div>
</template>
<style scoped>
h3 {
font-size: 26px;
border: 1px solid #ccc;
padding: 20px;
margin: 20px;
}
button {
float: right;
padding: 10px;
font-size: 20px;
}
</style>
计算属性有两种写法,作用和vue2一样,通过监听某个值的变化计算出一个新值
- 只读的写法 :computed(() => xxxxxx),
- 可读可写的写法: computed({ get: () => xxxx, set: (val) => { xxxx } })
<script setup>
import { ref, computed } from 'vue'
const count = ref(1)
const num1 = computed(() => count.value + 1)
const num2 = computed({
get() {
return count.value + 1
},
set(val) {
count.value = val + 1
},
})
</script>
<template>
<div>
<h1>v3</h1>
<h2>
ref 定义的 count: {
{ count }} <button @click="count++">count++</button>
</h2>
<h2>计算属性 num1: {
{ num1 }} <button @click="num1++">num1++</button></h2>
<h2>计算属性 num2: {
{ num2 }} <button @click="num2++">num2++</button></h2>
</div>
</template>
<style scoped></style>
watch 函数用来监听数据的变化,和vue2大体上都是相同的。
参数列表:
- 参数1为需要监听的响应式对象(可以是单个对象,也可以是一个数组,也可以是一个getter函数),
- 参数2为监听对象发生变化时所执行的回调
- 参数3是一些配置项:
immediate是否开启立即监听,deep是否开启深度监听,flush回调的触发时机,onTrack / onTrigger用于调试的两个函数
注意点:
<script setup>
import { reactive, ref, watch } from 'vue'
const count = ref(1)
const person = reactive({
name: 'ben',
child: {
son: {
name: 'zs',
},
},
})
// 监听 ref 对象
watch(count, (val, preVal) => {
console.log('count变化了', val, preVal)
})
// 监听 reactive 定义的响应式对象
watch(person, (val, preVal) => {
console.log('person变化了', val, preVal)
})
watch([count, person], (val, preVal) => {
console.log('person变化了或count变化了', val, preVal)
})
</script>
<template>
<div>
<h1>v3</h1>
<h2>
ref 定义的 count: {
{ count }} <button @click="count++">count++</button>
</h2>
<h2>
reactive 定义的 person: {
{ person }}
<button @click="person.name += '!'">修改姓名</button>
<button @click="person.child.son.name += '___'">修改儿子姓名</button>
</h2>
</div>
</template>
<style scoped></style>
watchEffect 函数用于监听传入的函数内访问的所有响应式数据的变化。白话一点就是回调里我用了谁我就监听谁,监听ref定义的响应式数据时,不要忘记 .value ,哥们就是这么智能。
watch 和 watchEffect 都是监听数据变化的函数,和 react 中的 useState 放入依赖项有着异曲同工之妙。
例子:切换下拉框中的 name ,模拟请求后台接口
<script setup>
import { onMounted, reactive, ref, watchEffect } from 'vue'
const name = ref('jack')
const info = [
{
id: 1,
name: 'jack',
child: {
son: {
name: 'zs',
},
},
},
{
id: 2,
name: 'ben',
child: {
son: {
name: 'zs',
},
},
},
]
let data = ref([])
async function getInfoByName(name) {
const res = await new Promise((reslove) => {
setTimeout(() => {
reslove(info.filter((item) => item.name === name))
}, 500)
})
data.value = res
}
watchEffect(async () => {
getInfoByName(name.value)
})
</script>
<template>
<div>
<h1>v3</h1>
<el-select v-model="name" placeholder="请选择">
<el-option
v-for="item in info"
:key="item.name"
:label="item.name"
:value="item.name"
>
</el-option>
</el-select>
<div v-for="item in data" :key="item.id">
{
{ item.name }}的个人信息 {
{ item }}
</div>
</div>
</template>
<style scoped></style>
vue3的生命周期稍有变动,增加了 setup 钩子,且销毁前和销毁后的钩子命名更改为 beforeUnmount 和 unmounted,以下代码是验证的一些示例
App.vue
<script setup>
import Demo from './Demo.vue'
import Demo2 from './Demo2.vue'
import { ref } from 'vue'
const isComDestory = ref(true)
const isOptionDestory = ref(true)
</script>
<template>
<div>
<h1>
v3
<button @click="isComDestory = false">引入组合式子组件</button>
<button @click="isComDestory = true">销毁组合式子组件</button>
<button @click="isOptionDestory = false">引入选项式子组件</button>
<button @click="isOptionDestory = true">销毁选项式子组件</button>
</h1>
<Demo v-if="!isComDestory"></Demo>
<Demo2 v-if="!isOptionDestory"></Demo2>
</div>
</template>
<style scoped>
button {
padding: 20px;
font-size: 16px;
}
</style>
Demo.vue
<script setup>
import {
onMounted,
onBeforeMount,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
ref,
} from 'vue'
const sum = ref(1)
console.log('子组件1 setup')
onBeforeMount(() => {
console.log('子组件1 onBeforeMount')
})
onMounted(() => {
console.log('子组件1 onMounted')
})
onBeforeUpdate(() => {
console.log('子组件1 onBeforeUpdate')
})
onUpdated(() => {
console.log('子组件1 onUpdated')
})
onBeforeUnmount(() => {
console.log('子组件1 onBeforeUnmount')
})
onUnmounted(() => {
console.log('子组件1 onUnmounted')
})
</script>
<template>
<div>
<h2>我是子组件1</h2>
<h2>{
{ sum }} <button @click="sum++">+1</button></h2>
</div>
</template>
<style scoped>
div {
border: 1px solid #ccc;
}
</style>
Demo2.vue
<script>
import { ref } from 'vue'
export default {
setup() {
const sum = ref(1)
console.log('子组件2 setup')
return { sum }
},
beforeCreate() {
console.log('子组件2 beforeCreate')
},
created() {
console.log('子组件2 created')
},
beforeMount() {
console.log('子组件2 beforeMount')
},
mounted() {
console.log('子组件2 mounted')
},
beforeUpdate() {
console.log('子组件2 beforeUpdate')
},
updated() {
console.log('子组件2 updated')
},
beforeUnmount() {
console.log('子组件2 beforeUnmount')
},
unmounted() {
console.log('子组件2 unmounted')
},
}
</script>
<template>
<div>
<h2>我是子组件2</h2>
<h2>{
{ sum }} <button @click="sum++">+1</button></h2>
</div>
</template>
<style scoped>
div {
border: 1px solid #ccc;
}
</style>
由于录频录不了控制台,打印结果看下图
vue3提供了两个api,限制响应式数据为只读,不可修改。分别为 readonly(深层只读) 和shallowReadonly (浅层只读)
<script setup>
import { ref, reactive, readonly, shallowReadonly } from 'vue'
const sum = readonly(ref(1))
const p1 = readonly(
reactive({
name: 'ben',
child: {
son: {
name: 'jack',
},
},
})
)
const p2 = shallowReadonly(
reactive({
name: 'ben',
child: {
son: {
name: 'jack',
},
},
})
)
function edit() {
sum.value = 2
p1.name += '!'
p1.child.son.name += '&'
}
function editShallow() {
p2.name += '!'
p2.child.son.name += '&'
}
</script>
<template>
<div>
<h1>v3</h1>
<h2>readonly: {
{ sum }}</h2>
<h2>readonly: {
{ p1 }}</h2>
<h2>shallowReadonly: {
{ p2 }}</h2>
<button @click="edit">修改深层只读数据</button>
<button @click="editShallow">修改浅层只读数据</button>
</div>
</template>
<style scoped></style>
toRaw的功能官网的解释很清晰, 可以返回由 reactive()、readonly()、shallowReactive() 或者 shallowReadonly() 创建的代理对应的原始对象
<script setup>
import {
ref,
reactive,
readonly,
shallowReadonly,
shallowReactive,
toRaw,
} from 'vue'
const p1 = readonly(
reactive({
name: 'a',
child: {
son: {
name: 'as',
},
},
})
)
const p2 = shallowReadonly(
reactive({
name: 'b',
child: {
son: {
name: 'bs',
},
},
})
)
const p3 = reactive({
name: 'c',
child: {
son: {
name: 'cs',
},
},
})
const p4 = shallowReactive({
name: 'd',
child: {
son: {
name: 'ds',
},
},
})
console.log('toRaw p1 readonly', toRaw(p1))
console.log('toRaw p2 shallowReadonly', toRaw(p2))
console.log('toRaw p3 reactive', toRaw(p3))
console.log('toRaw p4 shallowReactive', toRaw(p4))
</script>
<template>
<div></div>
</template>
<style scoped></style>
markRaw()将对象标记为不可代理,返回其本身。本身上多了一个 __v_skip 属性表示忽略代理。强行代理代理是无效的,返回的还是其本身而不是响应式对象。
<script setup>
import { markRaw, reactive } from 'vue'
const p1 = {
name: 'a',
child: {
son: {
name: 'as',
},
},
}
const noProxy_p1 = markRaw(p1)
console.log('不可代理对象', noProxy_p1)
console.log('reactive 代理不可代理对象', reactive(noProxy_p1))
</script>
<template>
<div></div>
</template>
<style scoped></style>
使用 provide 与 inject 进行跨组件传值十分方便。以父子孙为例,父组件 provide ('name',value) 子组件 inject ('name') 即可
父组件
<script setup>
import { reactive, provide } from 'vue'
import Demo from './Demo.vue'
const obj = {
name: 'a',
child: {
son: {
name: 'as',
},
},
}
const person = reactive(obj)
provide('person', person)
</script>
<template>
<div class="father">
<h1>父组件</h1>
<h3>{
{ person }}</h3>
<Demo></Demo>
</div>
</template>
<style scoped>
.father {
padding: 10px;
background: orange;
}
</style>
子组件
<script setup>
import Demo2 from './Demo2.vue'
</script>
<template>
<div>
<h2>子组件</h2>
<Demo2></Demo2>
</div>
</template>
<style scoped>
div {
padding: 10px;
background: salmon;
border: 1px solid #ccc;
}
</style>
孙组件
<script>
import { ref, inject } from 'vue'
export default {
setup() {
const person = inject('person')
return { person }
},
}
</script>
<template>
<div class="sonson">
<h2>孙组件</h2>
<h3>{
{ person }}</h3>
</div>
</template>
<style scoped>
.sonson {
background: sandybrown;
border: 1px solid #ccc;
}
</style>
- isRef(data)判断data是否是通过ref创建的响应式数据
- isReactive(data)判断data是否是通过reactive创建的响应式数据
- isReadonly(data)判断data是否是通过readOnly创建的只读数据
- isProxy(data)判断data是否为Proxy代理对象
<script setup>
import {
reactive,
readonly,
ref,
isProxy,
isReactive,
isRef,
isReadonly,
} from 'vue'
const person = reactive({
name: 'a',
child: {
son: {
name: 'as',
},
},
})
const num = ref(1)
const str = readonly(ref('str'))
console.log(isRef(num))
console.log(isReactive(person))
console.log(isReadonly(str))
console.log(isProxy(person), isProxy(str))
</script>
<template></template>
<style scoped></style>
当响应式对象的属性过多且页面用到很多次的时候, toRef 和 toRefs 可以进行响应式解构,解构出来的数据依旧具备响应式的能力。下面的例子是在 <script setup> 中进行演示的,setup()中的需要显示的返回
toRef
<script setup>
import { reactive, toRef } from 'vue'
const person = reactive({
name: 'a',
age: 18,
child: {
son: {
name: 'as',
},
},
})
const personName = toRef(person, 'name')
const personAge = toRef(person, 'age')
const personSonName = toRef(person.child.son, 'name')
</script>
<template>
<div>
<h3>toRef 解构出 person的name ----- {
{ personName }}</h3>
<h3>toRef 解构出 person的age ----- {
{ personAge }}</h3>
<h3>toRef 解构出 person的child的son的name ----- {
{ personSonName }}</h3>
<h3>toRef 解构出 person的name ----- {
{ personName }}</h3>
<h3>toRef 解构出 person的age ----- {
{ personAge }}</h3>
<h3>toRef 解构出 person的child的son的name ----- {
{ personSonName }}</h3>
<h3>toRef 解构出 person的name ----- {
{ personName }}</h3>
<h3>toRef 解构出 person的age ----- {
{ personAge }}</h3>
<h3>toRef 解构出 person的child的son的name ----- {
{ personSonName }}</h3>
<button @click="personName += '!'">修改person的name</button>
<button @click="personAge += 1">修改person的age</button>
<button @click="personSonName += '*'">person的child的son的name</button>
</div>
</template>
<style scoped></style>
toRefs
<script setup>
import { reactive, toRefs } from 'vue'
const person = reactive({
name: 'a',
age: 18,
child: {
son: {
name: 'as',
},
},
})
const { name, age, child } = toRefs(person)
</script>
<template>
<div>
<h3>toRefs 解构出 person的name ----- {
{ name }}</h3>
<h3>toRefs 解构出 person的age ----- {
{ age }}</h3>
<h3>toRefs 解构出 person的child的son的name ----- {
{ child.son.name }}</h3>
<h3>toRefs 解构出 person的name ----- {
{ name }}</h3>
<h3>toRefs 解构出 person的age ----- {
{ age }}</h3>
<h3>toRefs 解构出 person的child的son的name ----- {
{ child.son.name }}</h3>
<h3>toRefs 解构出 person的name ----- {
{ name }}</h3>
<h3>toRefs 解构出 person的age ----- {
{ age }}</h3>
<h3>toRefs 解构出 person的child的son的name ----- {
{ child.son.name }}</h3>
<button @click="name += '!'">修改person的name</button>
<button @click="age += 1">修改person的age</button>
<button @click="child.son.name += '*'">person的child的son的name</button>
</div>
</template>
<style scoped></style>
在vue2中模板标签内必须包裹一层根标签,vue3中则不需要。vue3会为多个跟标签包裹一层Fragment。这是写法上的优化。前面很多例子的代码中我都包裹了一层根标签,这是由于我的编辑器的eslint的问题,去掉根标签也可以正常运行。
有根标签的编译结果
没有根标签的编译结果
Teleport 组件的功能是将元素渲染到任意的页面位置中,直接扣过来官网的例子。
下列代码主要表达的是:点击按钮将弹框插入到 body 标签下
ModalButton.vue
<template>
<button @click="modalOpen = true">
Open full screen modal! (With teleport!)
</button>
<teleport to="body">
<div v-if="modalOpen" class="modal">
<div>
I'm a teleported modal! (My parent is "body")
<button @click="modalOpen = false">Close</button>
</div>
</div>
</teleport>
</template>
<script>
import { ref } from 'vue'
export default {
name: 'modal-button',
setup() {
const modalOpen = ref(false)
return {
modalOpen,
}
},
}
</script>
<style>
.modal {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.modal div {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: white;
width: 300px;
height: 300px;
padding: 5px;
}
</style>
App.vue
<template>
<h2>App</h2>
<modal-button></modal-button>
</template>
<script lang="ts">
import ModalButton from './ModalButton.vue'
export default {
setup() {
return {}
},
components: {
ModalButton,
},
}
</script>
Suspense 组件用于将异步组件包裹,提供一个过渡UI在异步完成之前。
Suspense 组件提供两个插槽:
- #default 默认插槽 存放异步组件
- #fallback 备用插槽 存放过渡UI
异步组件:
带有异步
setup()
钩子的组件。这也包含了使用<script setup>
时有顶层await
表达式的组件。defineAsyncComponent
App.vue
<template>
<div>
<h2>App</h2>
<Suspense>
<Demo></Demo>
<template #fallback> 加载中.... </template>
</Suspense>
</div>
</template>
<script setup>
import Demo from './Demo.vue'
</script>
Demo.vue
<script setup>
const res = await new Promise((resolve) => {
setTimeout(() => {
resolve({ name: 'zs', age: 12, sex: '男' })
}, 1000)
})
</script>
<template>
<div>
<h2>异步组件</h2>
<h3>{
{ res }}</h3>
</div>
</template>
<style scoped>
div {
padding: 10px;
background: salmon;
border: 1px solid #ccc;
}
</style>
组合式api的优点之一式将单个功能代码组合在一起,如果是可以复用的逻辑,那么可以抽离为一个组合式函数或者称为自定义hook,在需要该逻辑的地方导入即可
例子:提供一个组合函数,此函数在当前组件中监听鼠标移动事件,并将坐标显示出来,组件卸载前清掉事件。
App.vue
<template>
<div>
<h2>App</h2>
<h2>
<button @click="Demo1Visible = false">销毁子组件1</button>
<button @click="Demo2Visible = false">销毁子组件2</button>
</h2>
<Demo v-if="Demo1Visible"></Demo>
<Demo2 v-if="Demo2Visible"></Demo2>
</div>
</template>
<script setup>
import { ref } from 'vue'
import Demo from './Demo.vue'
import Demo2 from './Demo2.vue'
const Demo1Visible = ref(true)
const Demo2Visible = ref(true)
</script>
Demo1.vue
<template>
<div class="demo_1">
<h2>子组件1</h2>
<p v-if="x && y">x坐标为 {
{ x }}, y坐标为{
{ y }}</p>
</div>
</template>
<script setup>
import useMouse from './mouse'
const { x, y } = useMouse('.demo_1')
</script>
<style scoped>
.demo_1 {
height: 100px;
background: salmon;
}
</style>
Demo2.vue
<template>
<div class="demo_2">
<h2>子组件2</h2>
<p v-if="x && y">x坐标为 {
{ x }}, y坐标为{
{ y }}</p>
</div>
</template>
<script setup>
import useMouse from './mouse'
const { x, y } = useMouse('.demo_2')
</script>
<style scoped>
.demo_2 {
height: 100px;
background: salmon;
}
</style>
API 参考 | Vue.js,大家先自行参考,后续深入学习时再进行更新。
- 如果想在 vue3 中使用 element,请下载 element-plus
- vue3 的文档是最全的。Vue.js - 渐进式 JavaScript 框架 | Vue.js
文章浏览阅读3k次,点赞2次,收藏7次。企业架构师是使 IT 战略与业务目标保持一致的重要且不断增长的角色。无论您对云、应用程序、软件还是系统感兴趣,企业架构认证都可以提升您的职业生涯。如果您计划从事企业架构师 (EA) 的职业,那么认证是验证您的 EA 技能的好方法。作为 EA,您将负责为企业制定 IT 战略,以使业务目标与 IT 目标保持一致。公司严重依赖技术,因此 IT 现在是任何强大业务战略的基础部分。..._企业架构师认证
文章浏览阅读5.9k次,点赞2次,收藏29次。相比前两种搭建IP池的方法来说,付费代理IP更能满足用户的需求,但对于有些特殊要求的朋友来说,他们想一次提取很多个或者多次提取很多个,存放在本地建立的IP池里,这种方法在一定的程度上优化了方案。只不过长期下来的话,服务器的维护成本较高,并且需要定时的维护,消耗大量的时间,如果是个人的话,搭建起来后期维护的成本太高了,如果您不是高端玩家的话,不建议使用这种方式搭建IP池。相对于免费的代理IP来说,收费代理IP虽然需要付出一定的成本,但是IP资源都是真实IP,并且高匿性,稳定性也好。一、默认自动切换IP。..._如果制作代理ip池
文章浏览阅读4.3k次,点赞4次,收藏34次。本文主要是总结题主在学习与工作中使用到的Linux环境下解压与压缩命令,内容不算很全,但是囊括了大部分需求场景,如有误笔之处,还请同学指正。_linux解压rpm
文章浏览阅读451次,点赞11次,收藏8次。这里的按钮我是放在了table表格的末尾,目的是获取每一行中的批次号,然后根据批次号读取后台服务器的图片,并且展示在前端的dialog中。有图片的效果图,这里只是做了个测试,图片的大小暂时还未调整。主要是一个接口还有个工具类,代码如下。dialog部分的代码。_前端访问后端图片展示
文章浏览阅读3.4k次,点赞3次,收藏11次。win1803开始直接禁用驱动强制签名的方式不行了1.设置环境bcdedit -set NOINTEGRITYCHECKS ONbcdedit -set TESTSIGNING ONbcdedit -set loadoptions DDISABLE_INTEGRITY_CHECKS2.配置环境变量找到makecert.exe文件位置如【C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x64\makecert.exe】没有的请_免费驱动签名
文章浏览阅读1.1k次。云计算的三种主要服务模式——基础设施即服务(IaaS)、平台即服务(PaaS)和软件即服务(SaaS这三者在存储和资源池方面可以为企业提供的服务存在明显差异,但它们也可以相互交互以形成一个全面的云计算模型。1、基础设施即服务(IaaS)基础设施即服务有时缩写为IaaS,包含云IT的基本构建块,通常提供对联网功能、计算机(虚拟或专用硬件)以及数据存储空间的访问。基础设施即服务提供最高等级的灵活性和对IT资源的管理控制,其机制与现今众多IT部门和开发人员所熟悉的现有。_基础设施即服务(iaas)从部署的情况来分,可以分为那三种?
文章浏览阅读405次。1、官网的文档无论是学习Hadoop的hdfs、hive,还是hbase等,都要非常看重官网的文档。大数据的很多框架,都是Apache的顶级项目,各个组件框架的官网链接都可以从下面的链接进入:Hadoop:http://hadoop.apache.org/Avro: 序列化系统HBase: 分布式数据库Hive: 数据仓库Mahout: 机器学习与数据挖掘库Pig: 并行计算的高级数据..._方法论semma
文章浏览阅读411次,点赞8次,收藏21次。主题模型是自然语言处理和文本挖掘领域的一个重要研究方向,它可以自动发现文档集合中潜在的主题结构。其中,潜在狄利克雷分配(Latent Dirichlet Allocation, LDA)是最常用和最成功的主题模型之一。LDA是一种无监督的贝叶斯概率模型,能够有效地发现文档集合中隐藏的主题结构。LDA模型的核心思想是:每个文档可以表示为多个主题的概率分布,每个主题又可以表示为词语的概率分布。通过学习这些潜在的主题分布和词语分布,LDA模型可以发现文档集合中蕴含的语义主题信息。
文章浏览阅读2.3w次,点赞17次,收藏98次。目录一. 安装fitz二. pdf文件格式问题2.1 pdf文件存在多种格式2.2 分析问题三. 代码一. 安装fitz安装:需要安装fitz和PyMuPDF,否则会报如下错误:ModuleNotFoundError: No module named ‘frontend’pip install fitz PyMuPDF二. pdf文件格式问题2.1 pdf文件存在多种格式pdf文件的格式有好几种,用Adobe Acrobat比较正常的如下所示:这种类型的pdf文件可以比较正常地提取里面的图片_import fitz
文章浏览阅读5.4k次。除了while和do while循环,Java使用最广泛的是for循环。for循环的功能非常强大,它使用计数器实现循环。for循环会先初始化计数器,然后,在每次循环前检测循环条件,在每次循环后更新计数器。计数器变量通常命名为i。我们把1到100求和用for循环改写一下:// for----public class Main {public static void main(String[] arg..._java for 倒序
文章浏览阅读1w次,点赞6次,收藏10次。VS中未定义标识符vs2017中显示未定义标识符cout,endl。一种方法是:先看有没有包含输入输出流#include,以及命名空间using namespace std;第二种:如果上面都已包含,还是显示未定义标识符的话,检查一下,#include"pch.h"是否是在#include上面我就是犯了第二个错误..._未定义标识符 "endl
文章浏览阅读797次,点赞7次,收藏14次。如果你也是看准了Python,想自学Python,在这里为大家准备了丰厚的免费。_aescmac算法验证