解锁Vue组件的奇妙世界
文章目录
- 一、Vue 组件概述
- (一)什么是 Vue 组件
- (二)Vue 组件的优点
- 二、Vue 组件的创建方式
- (一)全局注册
- (二)局部注册
- (三)单文件组件(SFC)
- 三、Vue 组件的核心概念
- (一)Props(属性)
- (二)事件
- (三)插槽(Slots)
- (四)动态组件
- (五)生命周期钩子
- 四、Vue 组件的使用场景
- (一)UI 组件库
- (二)页面模块化
- (三)数据驱动应用
- (四)单页面应用(SPA)
- 五、Vue 组件的最佳实践
- (一)命名规范
- (二)单一职责
- (三)避免全局组件
- (四)使用 Prop 验证
- (五)尽量使用单文件组件
- 六、Vue 组件常见问题及解决方案
- (一)组件注册相关问题
- 组件未注册问题:
- 注册方式错误问题:
- 拼写或大小写错误问题:
- 异步组件未加载完成问题:
- (二)数据绑定与更新问题
- 视图不更新问题:
- (三)样式相关问题
- (四)跨域等其他问题
- 跨域问题:
一、Vue 组件概述
(一)什么是 Vue 组件
在 Vue.js 框架中,Vue 组件是一个核心概念,它可以被看作是构建用户界面的独立、可复用的基本构建单元,类似于 HTML 元素。通过将这些组件进行组合与嵌套,就能创建出复杂多样的用户界面。
每个 Vue 组件通常包含三个重要部分:
模板(Template)
:它主要用于定义组件呈现的 HTML 结构和布局,就像是给组件搭建了一个外在的框架,规定了组件长什么样,里面各个元素是如何排列展示的。例如,下面这段简单的模板代码定义了一个包含标题和段落的组件结构:
<template><div><h1>{{ title }}</h1><p>{{ content }}</p></div>
</template>
脚本(Script)
:这里面包含了组件的逻辑以及数据处理相关内容。比如通过 data 函数来定义组件内部使用的数据,通过 methods 来定义各种方法,实现相应的业务逻辑。以下是一个简单示例,展示了如何在脚本中定义数据和方法:
<script>
export default {data() {return {title: '示例组件',content: '这是组件展示的内容'};},methods: {updateTitle(newTitle) {this.title = newTitle;}}
};
</script>
样式(Style)
:顾名思义,就是用来定义组件的 CSS 样式,确定组件的外观风格,像颜色、字体大小、边距等等。例如:
<style>
h1 {color: blue;
}
p {font-size: 16px;
}
</style>
将这三个部分有机地组合在一起,开发者就能创建出独立且可复用的 UI 元素,并且可以方便地在不同的项目或者应用中重复使用这些组件,极大地提高了开发效率和代码的可维护性。
(二)Vue 组件的优点
模块化
:Vue 组件使得代码呈现出清晰的模块化结构。在开发大型项目时,我们可以将整个应用按照功能或者页面模块拆分成一个个独立的组件,每个组件负责自己特定的那部分功能和界面展示,就如同搭积木一样,各个积木块(组件)职责明确。例如在开发一个电商网站时,可以把产品展示、购物车、用户评论等不同功能分别开发成独立的组件,这样方便管理和维护代码,不同的开发人员也可以同时对不同的组件进行开发,提升了团队协作的效率。而且当出现问题时,由于模块边界清晰,能够快速定位到是哪个组件出现了问题,便于调试和修复。可重用性
:组件的一大亮点就是其可重用性。一旦创建好了一个组件,只要其他地方有相同的功能需求,就可以直接复用该组件,无需重复编写相同的代码。比如在一个多页面应用中,如果每个页面都有导航栏,那么我们只需要创建一个导航栏组件,然后在各个页面中都引入使用这个组件即可。要是后续需要对导航栏的样式或者功能进行修改,也只需要在定义该组件的地方进行调整,所有使用它的地方都会同步更新,大大减少了代码冗余,提高了开发效率,也保证了整个应用中相同功能模块的一致性。独立性
:每个组件都是相对独立的个体,具备自己独立的逻辑和样式,可以单独进行开发和测试。这意味着在开发组件时,开发人员不需要过多考虑其他组件的具体实现细节,只要遵循一定的接口规范(比如通过 props 接收外部传入的数据,通过 $emit 向外触发事件等),就能专注于当前组件功能的实现,降低了组件之间的耦合度,提高了代码的稳定性和可维护性。例如开发一个计数器组件,它内部的计数逻辑、显示逻辑等都是独立的,在测试时也可以单独对其进行单元测试,验证其功能是否正确。可组合性
:通过灵活地组合不同的组件,可以构建出复杂程度各异的用户界面。就像用各种简单的小零件(小组件),可以组装出功能强大、外观丰富的大型机器(复杂界面)一样。比如可以先创建按钮、输入框、列表等基础组件,然后将它们按照业务需求组合起来,形成一个完整的表单组件,再把表单组件和其他相关组件组合,搭建出一个页面的完整功能模块。这种可组合性使得代码具有很强的扩展性,方便应对不断变化的业务需求,能够快速地构建出复杂的应用程序。可维护性
:基于组件化的代码结构更加清晰易懂,每个组件的代码量相对较小,功能单一,便于阅读和理解,降低了代码的整体复杂度。当需要对应用进行维护或者更新时,比如添加新功能或者修改现有功能,只需要找到对应的组件进行相应的修改就可以了,不会影响到其他不相关的组件。例如,若要给某个页面添加一个新的交互功能,只需要在涉及该功能的组件内添加相应的代码逻辑,而不用担心会破坏整个页面或者其他组件的原有功能,使得代码的维护成本更低,更易于长期的项目迭代和优化。
二、Vue 组件的创建方式
(一)全局注册
在 Vue 中,使用 Vue.component(tagName, options)
进行全局注册组件。其中,tagName 是自定义的组件名称,后续可通过 <tagName></tagName>
这样的形式在模板中调用该组件;options 则是组件的配置对象,用于配置组件相关的各种属性,例如通过 template
来书写 HTML 代码(且必须有且只有一个根容器,不然会报错)等。
全局注册后的组件可以用在任何新创建的 Vue 根实例(new Vue
)的模板中,不过要注意必须在 vm
对象(即 Vue 实例)创建之前注册组件,否则虽然不会报语法错误,但组件不会被渲染出来。另外,组件的 data
属性值必须为一个函数,返回值为一个对象,这样能保证每个组件实例维护一份独立的数据拷贝,避免数据相互干扰。
以下是一个全局注册组件的示例代码:
// 先定义一个组件配置对象
const myComponent = {template: `<div><h1>这是一个全局组件示例</h1><p>{{ message }}</p></div>`,data() {return {message: '欢迎使用全局组件'};}
};
// 进行全局注册,组件名为 'my-global-component'
Vue.component('my-global-component', myComponent);// 创建Vue实例
new Vue({el: '#app'
});
然后在 HTML 模板中就能这样使用了:
<div id="app"><my-global-component></my-global-component>
</div>
(二)局部注册
局部注册组件是指在实例选项中进行注册,使得组件只能在特定的 Vue 实例中使用。
常见的做法是在创建 Vue 实例时,通过实例的 components
属性来注册局部组件。示例如下:
// 先定义组件配置对象
const myLocalComponent = {template: `<div><h2>这是一个局部组件示例</h2><p>{{ localMessage }}</p></div>`,data() {return {localMessage: '我是局部组件里的数据'};}
};new Vue({el: '#app',data: {},// 在components属性中注册局部组件,'local-component' 是在模板中使用的组件名,对应的值是组件配置对象components: {'local-component': myLocalComponent}
});
在对应的 HTML 模板中使用这个局部组件:
<div id="app"><local-component></local-component>
</div>
可以看到,这个名为 local-component
的组件就只能在当前这个 Vue 实例对应的模板中使用,无法在其他 Vue 实例的模板里直接调用,体现了局部组件使用范围的局限性。
(三)单文件组件(SFC)
单文件组件(.vue
文件)是 Vue 推荐的一种组件定义方式。它将一个组件相关的 HTML 结构(写在 <template>
标签内)、CSS 样式(写在
<template><div class="hello-world"><h1>{{ msg }}</h1><p>这是一个单文件组件示例</p></div>
</template><script>
export default {name: 'HelloWorld',data() {return {msg: 'Hello, Vue!'};}
};
</script><style>
.hello-world {background-color: #f5f5f5;padding: 20px;border-radius: 5px;
}
</style>
不过,浏览器本身并不能直接识别 .vue 文件,需要借助如 Vue CLI 这样的工具来处理这些文件,将其编译打包成浏览器能识别的 JavaScript 等资源文件。
在项目中使用单文件组件时,比如在另一个组件或者 Vue 实例中引入并使用上述的 HelloWorld.vue
组件,示例代码如下:
import HelloWorld from './HelloWorld.vue';new Vue({el: '#app',components: {HelloWorld}
});
对应的 HTML 模板里这样使用:
<div id="app"><hello-world></hello-world>
</div>
通过这种方式,就能方便地将各个功能独立的单文件组件组合起来,构建出复杂的应用界面。
三、Vue 组件的核心概念
(一)Props(属性)
在 Vue 组件中,Props
(属性)起着向子组件传递数据的关键作用。它允许父组件将数据以属性的形式传递给子组件,使得子组件能够根据接收到的数据进行相应的展示或逻辑处理。
我们可以通过 props
选项来定义组件能够接收的属性。例如,创建一个名为 ChildComponent
的子组件,在其配置对象中通过 props
定义接收的属性:
export default {props: {message: String,count: Number},template: `<div><p>{{ message }}</p><p>计数: {{ count }}</p></div>`
};
在上述代码中,ChildComponent
组件定义了两个 props,分别是 message
(类型为字符串)和 count
(类型为数字)。
然后在父组件中使用这个子组件,并传递相应的数据:
<template><div><ChildComponent :message="parentMessage" :count="parentCount" /></div>
</template><script>
import ChildComponent from './ChildComponent.vue';
export default {components: {ChildComponent},data() {return {parentMessage: '这是来自父组件的消息',parentCount: 5};}
};
</script>
在父组件的模板里,通过 v-bind(缩写为 :)将 parentMessage
和 parentCount
这两个数据绑定到子组件的 message 和 count 属性上,这样就完成了从父组件向子组件的数据传递。子组件接收到数据后,就能在自己的模板中进行展示了。
(二)事件
Vue 组件间的通信除了通过 Props 传递数据外,事件机制也是常用的方式。子组件可以通过 $emit 方法触发事件,而父组件则通过 v-on(缩写为 @)来监听这些事件,从而实现组件间的双向通信。
例如,创建一个名为 ButtonComponent 的子组件,当按钮被点击时,触发一个自定义事件:
<template><button @click="handleClick">点击我</button>
</template><script>
export default {methods: {handleClick() {this.$emit('button-clicked', '按钮被点击啦');}}
};
</script>
在上述子组件代码中,定义了 handleClick
方法,当按钮被点击时,通过 $emit
触发名为 button-clicked
的事件,并可以传递一个参数(这里传递了一个简单的字符串消息)。
然后在父组件中监听这个事件:
<template><div><ButtonComponent @button-clicked="showMessage" /></div>
</template><script>
import ButtonComponent from './ButtonComponent.vue';
export default {components: {ButtonComponent},methods: {showMessage(message) {alert(message);}}
};
</script>
在父组件模板里,通过 @button-clicked
监听子组件触发的 button-clicked
事件,并在对应的 showMessage
方法中接收子组件传递过来的参数,这里简单地弹出一个提示框展示消息。通过这样的机制,组件间就能方便地进行交互通信了。
(三)插槽(Slots)
插槽(Slots
)是 Vue 组件中一个很实用的特性,它允许我们在组件内部插入内容,使得组件更加灵活可复用。
比如创建一个简单的 CardComponent
组件,它内部定义了一个插槽:
<template><div class="card"><slot></slot></div>
</template><style>
.card {border: 1px solid #ccc;padding: 10px;border-radius: 5px;
}
</style>
在上述代码中, 标签在组件模板里占据了一个位置,相当于一个 “占位符”。
然后在父组件使用这个 CardComponent 组件时,就可以往插槽里插入内容了:
<template><div><CardComponent><h2>这是卡片标题</h2><p>这是卡片内容部分,通过插槽插入到组件内部了。</p></CardComponent></div>
</template><script>
import CardComponent from './CardComponent.vue';
export default {components: {CardComponent}
};
</script>
在父组件的 CardComponent
标签内写入的内容,就会替换掉子组件中 <slot>
所在的位置,从而实现了在组件内部插入自定义内容的效果,让组件可以根据不同的使用场景展示不同的内容,增强了组件的复用性和灵活性。
(四)动态组件
在 Vue 中,我们可以使用 <component>
元素和 is 特性来实现动态切换组件。这种方式在需要根据不同条件展示不同组件的场景下非常有用。
例如,有两个组件 ComponentA
和 ComponentB
,我们希望根据用户的操作或者某个变量的值来切换显示这两个组件:
// 定义ComponentA组件
const ComponentA = {template: `<div>这里是ComponentA的内容</div>`
};// 定义ComponentB组件
const ComponentB = {template: `<div>这里是ComponentB的内容</div>`
};new Vue({el: '#app',data: {currentComponent: 'ComponentA'},components: {ComponentA,ComponentB}
});
在上述代码中,首先定义了两个简单的组件 ComponentA
和 ComponentB
,然后在 Vue 实例的数据选项中定义了 currentComponent
变量,用于控制当前要显示的组件。
在 HTML 模板中,通过 <component>
元素结合 is 特性来实现动态切换:
<template><div><button @click="changeComponent('ComponentA')">显示ComponentA</button><button @click="changeComponent('ComponentB')">显示ComponentB</button><component :is="currentComponent"></component></div>
</template><script>
export default {methods: {changeComponent(componentName) {this.currentComponent = componentName;}}
};
</script>
当点击不同的按钮时,会调用 changeComponent 方法改变 currentComponent 的值,从而让 元素动态地切换显示对应的组件,满足不同场景下的页面展示需求。
(五)生命周期钩子
Vue 组件的生命周期钩子是在组件不同阶段自动调用的一系列方法,它们可以帮助开发者在组件的各个关键阶段执行特定的逻辑,比如进行初始化操作、DOM 相关操作、处理组件更新以及销毁时的清理工作等。
常用的生命周期钩子有以下几个:
beforeCreate:在实例初始化之后,数据观测(data observer)和事件配置之前被调用。这个阶段组件的选项对象已经配置好了,但还没办法访问到数据和 DOM 相关的内容。
created:在实例创建完成后被立即调用。此时实例已完成数据观测(data observer)、属性和方法的运算、watch/event 事件回调等配置,但挂载阶段还没开始,$el 属性目前不可见。例如,我们可以在这个钩子中进行一些初始化的数据获取或者设置操作,像调用接口获取初始数据等,代码示例如下:
export default {created() {// 在这里发起获取数据的请求等初始化操作this.fetchInitialData();},methods: {fetchInitialData() {// 模拟发送请求获取数据console.log('正在获取初始数据...');}}
};
beforeMount
:在挂载开始之前被调用,相关的 render 函数首次被调用。mounted
:实例被挂载后调用,这时$el
已经被创建并插入到 DOM 中了。如果根实例挂载到一个文档内的元素上,当mounted
被调用时vm.$el
也在文档内。这个钩子常用于执行 DOM 相关的操作,比如获取某个 DOM 元素,添加事件监听器等,示例如下:
export default {mounted() {const myElement = this.$el.querySelector('.my-class');if (myElement) {myElement.addEventListener('click', this.handleClick);}},methods: {handleClick() {console.log('元素被点击了');}}
};
beforeUpdate
:数据更新时调用,发生在虚拟 DOM 重新渲染和修补之前。可以在这个钩子中进一步地修改状态,不会触发附加的重渲染过程。updated
:由于数据更改导致的虚拟 DOM 重新渲染和修补后会调用此钩子。beforeUnmount
:实例销毁之前调用。在这个阶段,实例仍然完全可用,我们可以在这里执行一些清理工作,比如移除事件监听器等。unmounted
:实例销毁后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。
合理使用这些生命周期钩子函数,能够更好地管理组件的状态和行为,让组件的功能实现更加完善和可控。
四、Vue 组件的使用场景
(一)UI 组件库
在 Vue 项目开发中,UI 组件库发挥着重要作用,比如 Element UI
和 Vuetify
这两个非常流行的 UI 组件库,为开发者提供了大量预定义组件,能够助力快速开发出美观且功能完善的用户界面。
Element UI
是由饿了么前端团队开发的一套基于 Vue.js 的组件库,它有着诸多优势。其组件丰富,涵盖了按钮、表单、弹窗、导航等常见的 UI 需求,无论是构建响应式网页,还是打造复杂的应用程序,开发者都能从中轻松找到合适的组件来使用。而且它的使用十分便捷,组件设计简洁明了,配合详细的文档和示例,开发者可以快速上手,迅速搭建出漂亮的界面。此外,Element UI 还具备高度可定制的特点,组件拥有丰富的配置选项,开发者能够依据项目的具体需求,灵活地对主题、样式或者组件进行定制,满足特定的设计要求。同时,作为一个活跃的开源项目,它有着庞大的社区支持,社区提供的大量插件、扩展和第三方库,进一步丰富了它的功能和特性,适用于企业级应用、管理后台、数据展示类网站等各种类型的项目。Vuetify
则是一个基于 Vue.js 且遵循Material Design
设计规范的响应式 UI 框架。它同样提供了大量的 UI 组件和样式,基于其开发的应用程序往往具有现代化的外观以及良好的用户体验。Vuetify 支持响应式布局,能够根据不同的屏幕尺寸和设备类型自动调整布局,确保应用程序在各类设备上都能为用户提供一致的体验。在主题定制方面,它也表现出色,开发者可以根据项目需求对颜色、样式和布局等进行自定义,轻松使应用程序与品牌风格相契合。凭借庞大的社区支持,开发者可以从社区提供的大量文档、示例和插件中获取帮助,加快开发速度,特别适合开发管理后台、企业级应用、数据可视化等应用程序。
使用这些 UI 组件库,开发者无需从头开始编写各种基础组件,只需按照文档引入并配置相应组件,就能快速搭建起页面的基本架构,极大地提高了开发效率,让项目能够更快地交付使用。
(二)页面模块化
将页面拆分为多个独立组件是 Vue 组件化开发的一个重要应用场景,这样做有着诸多好处。
代码的可管理性会因为页面模块化得到显著提升。以一个电商网站为例,整个页面可以按照不同的功能模块拆分成诸如产品展示组件、购物车组件、用户评论组件等。每个组件负责自己特定部分的功能实现和界面展示,就如同搭积木一样,各个积木块(组件)职责清晰明确。在大型项目中,不同的开发人员可以同时对不同的组件进行开发,互不干扰,提升了团队协作的效率。而且当出现问题时,由于模块边界清晰,能够快速定位到是哪个组件出现了问题,便于调试和修复。
例如,在开发一个包含商品列表、商品详情以及用户购买流程的电商页面时,可以把商品列表部分作为一个独立组件,它内部负责从服务器获取商品数据、展示商品的基本信息等功能;商品详情页作为另一个组件,专注于展示某个商品的详细信息,如图片、参数、介绍等;购买流程组件则处理用户选择商品规格、数量,提交订单等相关逻辑。通过这样的划分,每个组件的代码量相对较小,功能单一,便于阅读和理解,降低了代码的整体复杂度。当后续需要对某个功能进行修改或者扩展时,比如要给商品列表添加一个筛选功能,只需要在商品列表组件内添加相应的代码逻辑即可,不会影响到其他不相关的组件,使得代码的维护成本更低,更易于长期的项目迭代和优化。
(三)数据驱动应用
Vue 组件在数据展示和操作方面有着广泛的应用场景,特别是在表单、图表、列表等应用场景中体现得尤为明显。
在表单应用中,比如我们要创建一个用户注册表单,通过组件可以方便地实现数据的双向绑定。首先创建输入框组件、单选框组件、复选框组件等基础表单组件,然后将它们组合起来构成完整的注册表单组件。示例代码如下:
<template><form><input-component v-model="user.name" label="用户名" /><input-component v-model="user.password" label="密码" type="password" /><radio-component v-model="user.gender" label="性别" :options="genderOptions" /><checkbox-component v-model="user.hobbies" label="爱好" :options="hobbyOptions" /><button @click="submitForm">提交</button></form>
</template><script>
import InputComponent from './InputComponent.vue';
import RadioComponent from './RadioComponent.vue';
import CheckboxComponent from './CheckboxComponent.vue';export default {components: {InputComponent,RadioComponent,CheckboxComponent},data() {return {user: {name: '',password: '',gender: '',hobbies: []},genderOptions: ['男', '女'],hobbyOptions: ['阅读', '运动', '音乐']};},methods: {submitForm() {// 这里可以编写提交表单数据的逻辑,比如发送请求到服务器console.log('提交表单数据:', this.user);}}
};
</script>
在上述代码中,各个自定义的表单组件通过v-model
指令实现了数据的双向绑定,方便用户输入数据以及获取用户输入的数据进行后续处理。
对于图表展示场景,假设有一个展示销售数据的柱状图组件,它接收一个包含销售数据的数组作为属性,然后在组件内部根据数据绘制出对应的柱状图。代码示例可能如下:
<template><div class="chart-container"><canvas id="sales-chart"></canvas></div>
</template><script>
import Chart from 'chart.js';export default {props: {salesData: {type: Array,required: true}},mounted() {const ctx = document.getElementById('sales-chart').getContext('2d');new Chart(ctx, {type: 'bar',data: {labels: ['一月', '二月', '三月', '四月'],datasets: [{label: '销售额',data: this.salesData,backgroundColor: 'rgba(75, 192, 192, 0.2)',borderColor: 'rgba(75, 192, 192, 1)',borderWidth: 1}]},options: {scales: {y: {beginAtZero: true}}}});}
};
</script><style>
.chart-container {width: 400px;height: 300px;
}
</style>
通过将数据传递给图表组件,就能动态地展示不同的销售数据情况。
在列表展示方面,比如展示文章列表,创建一个文章列表组件,接收一个文章数据数组作为属性,循环渲染出每篇文章的标题、摘要等信息,方便进行数据展示和交互操作。总之,Vue 组件能够很好地基于数据进行各种应用的构建,实现丰富多样的数据驱动应用场景。
(四)单页面应用(SPA)
在构建单页面应用(SPA)时,Vue Router 起着关键的辅助作用,它帮助我们利用组件来高效地管理页面和路由。
Vue Router 是 Vue.js 官方提供的路由管理插件,支持嵌套路由、路由参数、导航守卫等功能,能轻松实现单页面应用的路由管理。例如,我们要构建一个简单的 SPA 应用,包含首页、关于页面和文章详情页面这几个部分。
首先,定义各个组件:
// 首页组件
const Home = {template: `<div><h2>这是首页</h2><router-link to="/about">去到关于页面</router-link></div>`
};// 关于页面组件
const About = {template: `<div><h2>这是关于页面</h2><router-link to="/article/1">查看文章详情(示例文章1)</router-link></div>`
};// 文章详情组件(这里简单示例,接收文章id作为参数)
const ArticleDetail = {props: ['articleId'],template: `<div><h2>文章详情页,文章ID:{{ articleId }}</h2><router-link to="/">返回首页</router-link></div>`
};
然后配置路由:
import Vue from 'vue';
import Router from 'vue-router';Vue.use(Router);export default new Router({routes: [{ path: '/', component: Home },{ path: '/about', component: About },{ path: '/article/:articleId', component: ArticleDetail, props: true }]
});
在上述代码中,通过定义不同的路径和对应的组件,建立起了路由关系。
在 HTML 模板中,使用 组件来创建链接进行页面导航, 标签则作为路由匹配的组件渲染的出口。示例如下:
<template><div><router-link to="/">首页</router-link><router-view></router-view></div>
</template><script>
export default {
};
</script>
当用户点击不同的链接时,Vue Router
会根据配置的路由规则,动态地加载对应的组件并展示在 <router-view>
位置,实现无刷新的页面切换效果,构建出流畅的单页面应用体验。这样的方式让整个应用的页面管理更加清晰、灵活,方便开发者根据业务需求不断扩展和优化应用的页面结构和功能。
五、Vue 组件的最佳实践
(一)命名规范
在 Vue 开发中,良好的命名规范对于提高代码的可读性、可维护性以及协作性都非常重要,而组件命名规范是其中关键的一环。
组件名应该采用帕斯卡命名法(PascalCase
),也就是每个单词的首字母都大写,且名称要具有描述性,能够清楚地表达组件的用途。同时,要避免使用与 HTML 元素相同的名称,以免引起混淆。
例如,下面是错误的命名方式:
<template><div><mybutton></mybutton></div>
</template>
这里使用了 mybutton
作为组件名,不符合帕斯卡命名法,而且表意不够清晰准确。
正确的命名示例如下:
<template><div><MyButton></MyButton></div>
</template>
像这样使用 MyButton
作为组件名,遵循了帕斯卡命名法,让人一眼就能大概了解这个组件可能是一个按钮相关的组件,方便后续代码的阅读与维护等操作。
(二)单一职责
单一职责原则在 Vue 组件开发中是非常重要的理念,它要求每个组件只负责一个功能。
如果一个组件承担了过多复杂的功能,那么开发过程中就会变得难以把控,代码也容易变得混乱,不利于后续的维护与扩展。而且在出现问题时,很难快速定位是哪部分功能出现了故障,调试的难度会大大增加。
例如,假设有一个组件,它既负责从服务器获取用户数据,又要展示用户的详细信息,同时还处理用户对这些信息的各种编辑操作,这样功能复杂的组件就违背了单一职责原则。
而遵循单一职责原则的正例可以看下面这个场景:比如我们有一个需求,需要展示用户的信息,并在组件挂载时获取用户数据。按照单一职责原则,我们可以将这个需求分成两个组件。一个是负责展示用户信息的 UserDisplay.vue 组件,代码如下:
<template><div class="user-display"><h2>{{ user.name }}</h2><p>{{ user.email }}</p></div>
</template><script>
export default {name: 'UserDisplay',props: {user: {type: Object,required: true}}
};
</script><style scoped>
.user-display {border: 1px solid #ccc;padding: 10px;border-radius: 5px;
}
</style>
这个组件只专注于展示用户的信息,通过 props
接收外部传入的用户数据对象进行展示,不涉及数据获取等其他逻辑。
另一个是负责获取用户数据并传递给展示组件的 UserContainer.vue
组件,代码如下:
<template><div><UserDisplay v-if="user" :user="user" /><p v-else>Loading...</p></div>
</template><script>
import UserDisplay from './UserDisplay.vue';
export default {name: 'UserContainer',components: {UserDisplay},data() {return {user: null};},async mounted() {const response = await fetch('https://xxx.com/users/1');const data = await response.json();this.user = data;}
};
</script><style scoped>
p {text-align: center;
}
</style>
该组件在挂载时去获取用户数据,获取到后再传递给 UserDisplay
组件进行展示,各司其职,使得每个组件的功能都很清晰明确,便于开发、测试以及后续的维护与复用等操作,更好地遵循了单一职责原则。
(三)避免全局组件
在 Vue 项目中,我们应尽量使用局部注册组件,这样可以减少全局命名空间污染。
全局注册组件虽然使用起来比较方便,在任何新创建的 Vue 根实例的模板中都能直接使用,但它存在一些弊端。比如全局注册但并没有被实际使用的组件无法在生产打包时被自动移除(也叫 “tree-shaking”),这会导致打包后的文件体积无端增大,包含了很多无用的代码。而且在大型项目中,过多地使用全局注册会使项目的依赖关系变得不那么明确,就如同使用过多的全局变量一样,不利于长期的项目维护,后期想要理清各个组件之间的关系以及排查问题都会变得困难。
例如,在一个大型的企业级应用中,如果大量使用全局组件,随着项目不断迭代,组件数量越来越多,可能会出现很多组件虽然注册了但在实际应用中根本没用到的情况,这些冗余的组件就会一直存在于打包文件里,增加了不必要的资源开销。同时,开发人员在查看代码逻辑时,很难直观地判断出某个全局组件具体是在哪里被使用以及和其他组件的关联情况。
而采用局部注册组件,能使组件之间的依赖关系更加明确,并且对 “tree-shaking” 更加友好,只有被实际引入并使用的组件才会被打包进最终的文件中,使得项目结构更加清晰,便于维护和管理,所以在实际开发中要尽量避免过多地使用全局组件,优先选择局部注册的方式来使用组件。
(四)使用 Prop 验证
在 Vue 组件间进行数据传递时,Prop 验证是一项很重要的机制,我们可以通过 props 选项来验证传入数据的类型等信息。
比如,我们可以这样定义 props 来验证数据类型:
export default {props: {age: {type: Number,required: true}}
}
在上述代码中,age
这个 prop
被指定为 Number
类型且是必需的,如果父组件传递给子组件的 age prop
不是一个数字类型,Vue.js 会在控制台中抛出警告。
再看一个稍微复杂一点的例子,包含多种验证规则的使用:
props: {age: {type: Number,required: true,default: 18,validator: function (value) {return value >= 0;}}
}
这里 age prop 除了指定类型和必需属性外,还提供了默认值和自定义验证函数,确保 age prop 始终是一个非负数。
通过 Prop 验证,能确保数据类型的一致性,让组件接收到符合预期的数据格式,避免因为数据类型不匹配等问题导致组件出现异常情况,极大地提高了代码的可维护性。同时,在开发过程中,能帮助开发者更早地发现和修复错误,防止这些错误在生产环境中引发更严重的问题,增强了整个应用的健壮性,所以在合适的场景下,合理使用 Prop 验证是非常有必要的。
(五)尽量使用单文件组件
单文件组件(.vue 文件)是 Vue 推荐的一种组件定义方式,它有着诸多优势,便于我们对组件的模板、脚本和样式进行管理。
与其他将模板、脚本、样式分散在不同文件或者以其他复杂形式组织的方式相比,单文件组件把相关的 HTML 结构(写在 <template>
标签内)、CSS
样式(写在 <style>
标签内)以及交互的 JavaScript 代码(写在<script>
标签内)都封装在一个文件里,使得组件的结构更加清晰直观。例如,我们创建一个简单的计数器单文件组件 Counter.vue
:
<template><div><p>{{ count }}</p><button @click="incrementCount">增加计数</button></div>
</template><script>
export default {data() {return {count: 0};},methods: {incrementCount() {this.count++;}}
};
</script><style scoped>
h1 {color: blue;
}
</style>
从这个示例可以看出,开发人员在查看这个组件时,无需在多个不同的文件之间来回切换查找,就能很方便地了解组件的完整逻辑、展示结构以及样式设定,提升了代码的可读性和可维护性。
在实际项目中,比如开发一个电商网站,会有商品列表组件、购物车组件等众多组件,使用单文件组件的形式,每个组件都独立封装在一个 .vue 文件里,不同的开发人员可以分别专注于各自负责的单文件组件开发,然后通过合理的引入和组合,就能快速搭建起整个项目的页面架构,而且后续如果需要对某个组件进行修改或者扩展功能,也能很容易定位到对应的 .vue 文件进行操作,不会影响到其他不相关的组件,所以单文件组件在项目管理方面有着显著的优势,值得我们在 Vue 项目开发中尽量去使用。
六、Vue 组件常见问题及解决方案
(一)组件注册相关问题
在使用 Vue 组件的过程中,组件注册方面常常会出现一些问题导致使用时报错。
组件未注册问题:
比如在使用像 Ant Design Vue
框架时,正常配置后使用一些基础组件没问题,但使用某些组件(如 <a-transfer>
穿梭框组件)会突然报错 [Vue warn]: Unknown custom element: <a-transfer> - did you register the component correctly? For recursive components, make sure to provide the "name" option。
这可能是因为框架为了减少编译支持库包大小,这些 “报错组件” 是按需加入的,默认不加载,需要手动添加。解决办法是依次打开项目文件夹【src】→【core】,找到【core】文件夹下的按需加载配置文件(如 lazy_use.js,不同项目文件名可能不同),然后加入 “未注册的组件”,组件列表可参照官网(https://github.com/vueComponent/ant-design-vue/blob/master/components/index.js )。
另外,如果在 Vue 项目中引入自定义组件报错组件未注册,还需要检查引入代码是否正确。例如,错误的引入方式像 import {ischemicHeart} from "@/components/ischemicHeart/index"
,正确的应该是 import ischemicHeart from "@/components/ischemicHeart/index"
,要注意自定义的组件在别处引入不需要中括号,和引入第三方组件的方式有所区别。
注册方式错误问题:
比如在使用动态组件时,像下面这样的代码:
<template><div><div v-for="(item, index) in list" :key="index"><component :is="item"></component></div></div>
</template>
<script>
// 先把组件引入
import ImageComponent from './Image.vue'
import TextComponent from './Text.vue'
import VideoComponent from './Video.vue'
export default {components: {ImageComponent,TextComponent,VideoComponent},data () {return {list: ['ImageComponent', 'TextComponent', 'VideoComponent']}}
}
</script>
如果出现 Unknown custom element
这样的报错,提示组件没注册正确,可能需要在生命周期的 beforeCreate
方法中临时注册一下组件,比如:
beforeCreate() {this.$options.components.ImageComponent = require('./ImageComponent.vue').default
}
拼写或大小写错误问题:
当注册组件或者在模板中使用组件时,如果组件名称拼写错误或者大小写不一致,Vue 是无法正确识别组件的,会报类似组件未注册的错误。所以在书写组件名称时一定要仔细核对,保证和注册时的名称完全一致。
异步组件未加载完成问题:
如果使用了异步加载的组件,在组件还未加载完成时就去使用它,也会出现问题。此时可以通过添加加载提示等方式,让用户知晓组件正在加载,或者检查异步加载的配置是否正确,确保组件能正常加载完成后再使用。
总之,不同的组件注册相关问题有不同的报错提示,开发者需要仔细查看控制台报错信息,分析原因,然后采取对应的解决方法来让组件能正常使用。
(二)数据绑定与更新问题
在 Vue 组件的数据方面,也容易出现一些常见问题。
函数返回对象要求问题:
在 Vue 实例内,单组件的 data 必须返回一个对象。例如:
export default {name: 'page-router-view',data () {return {tabs: [{title: '财务信息',url: '/userinfo'}, {title: '帐号信息',url: '/userinfo/base'}]}}
}
这是因为组件可能被用来创建多个实例,如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象,在组件复用下容易造成数据相互影响的问题。
视图不更新问题:
当我们在 Vue 组件中使用 v-model 指令来实现双向数据绑定,方便地在组件和父组件之间传递数据时,有时候会遇到通过修改组件内部的数据,却无法触发 v-model 绑定的数据更新,从而造成视图与数据不同步的情况。这是因为 Vue 并不会为组件内部的普通对象或数组自动创建响应式属性。比如下面这种情况,直接修改组件内普通对象或数组,视图可能不会更新:
// 假设组件内有这样的数据
data() {return {myObject: {key: 'value'},myArray: [1, 2, 3]}
}
// 直接修改对象或数组,像这样
this.myObject.key = 'newValue';
this.myArray.push(4);
解决方法是要手动告诉 Vue,某个属性已经被修改了,Vue 提供了 $set
方法来实现这个功能,用法如下:
this.$set(object, key, value);
// 例如,针对上面的对象修改,可以写成
this.$set(this.myObject, 'key', 'newValue');
通过这种方式来确保数据修改能被 Vue 监听到,进而触发视图更新,保证数据和视图的一致性。
(三)样式相关问题
在单组件开发模式下,有时会遇到样式不能继承或覆写的情况。
这主要是因为在单组件开发中,如果开启了 css 模块化功能(也就是 scoped 属性,在 vue-cli 里面配置了,只要加入这个属性就自动启用),每个类或者 id 乃至标签都会自动在 css 后面添加 hash。比如,原本写的时候是 .trangle{} ,编译过后,会变成 .trangle[data-v-1ec35ffc]{}
。
例如在一个 .vue 文件中定义了样式:
<template><div class="my-component"><p>这是组件内的内容</p></div>
</template>
<style scoped>
.my-component {color: red;
}
</style>
如果想在外部或者其他组件中覆写这个 .my-component 的样式就会发现无法覆写,就是因为这个 scoped 属性导致的样式隔离。
解决办法就是根据实际需求来合理调整相关配置。如果确实需要某个样式能被外部继承或者覆写,可以考虑去除 scoped 属性,但要注意这样可能会影响到全局的样式作用范围,容易造成样式冲突。或者通过一些更细化的 css 选择器权重等方式来实现特定的样式调整需求,确保样式能按照预期进行展示和复用。
(四)跨域等其他问题
在 Vue 项目开发中,还会遇到像跨域、在 IE 浏览器中部分功能不识别等其他常见问题。
跨域问题:
跨域问题指的是在浏览器端,当一个网页的脚本(如 JavaScript)向另一个域名的网站发起请求时,如果两个网站的域名不一致,就会出现跨域问题。由于浏览器的同源策略(Same Origin Policy),默认情况下,脚本只能访问同一个域名下的资源,不能访问其他域名下的资源。常见的跨域场景比如协议跨域(如 http://a.baidu.com 访问 https://a.baidu.com )、端口跨域(如 http://a.baidu.com:8080 访问 http://a.baidu.com:80 )、域名跨域(如 http://a.baidu.com 访问 http://b.baidu.com )。
解决跨域问题有以下几种常见思路和方法:
CORS(Cross-Origin Resource Sharing)
:它是一种跨域资源共享的机制,可以用于解决跨域问题。CORS 机制允许服务器在响应中设置一个 Access-Control-Allow-Origin 头部,来指定允许哪些域名访问资源。例如,在服务器端向每一个响应添加如下头部信息来指定允许访问的域名等:
Access-Control-Allow-Origin: http://www.example.com,https://www.example.com
Access-Control-Allow-Methods: GET,POST,OPTIONS
Access-Control-Allow-Headers: Content-Type
不过要注意,CORS 机制只能用于浏览器端,即仅限于 XMLHttpRequest 和 Fetch API 这两种请求。而且需要后端配合开启 cors ,不同的后端语言都有对应的实现方式,比如 NodeJS 的 koa2-cors ,使用方式如下:
var koa = require('koa');
// npm install --save koa2-cors
var cors = require('koa2-cors');
var app = koa();
// 开启
app.use(cors());
Nginx 反向代理
:Nginx 是一款高性能的 Web 服务器和反向代理服务器,可以用于解决跨域问题。具体实现方法是在 Nginx 的配置文件中添加反向代理规则,将请求转发到目标服务器,并将响应返回给客户端。示例配置如下:
server {listen 80;server_name www.example.com;location /api {add_header 'Access-Control-Allow-Origin' '*';add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';proxy_pass http://api.example.com;}
}
通过这样的配置将客户端请求转发到 http://api.example.com
,同时设置响应头信息,实现跨域访问。
JSONP
:它(JSON with Padding)是一种在客户端与服务器之间进行跨域数据传输的解决方案,利用了
// ES6的polyfill
require("es6-promise").polyfill();
总之,针对不同的其他常见问题,需要根据其特点和适用场景来选择合适的解决方法,确保项目能正常运行和展示。
更多细节及方法,还需要大家仔细阅读官方文档!
相关文章:
解锁Vue组件的奇妙世界
文章目录 一、Vue 组件概述(一)什么是 Vue 组件(二)Vue 组件的优点 二、Vue 组件的创建方式(一)全局注册(二)局部注册(三)单文件组件(SFC…...
二分查找【Lecode_HOT100】
文章目录 1.搜索插入位置No.352.搜索二维矩阵No.743.在排序数组中查找元素的第一个和最后一个位置No.344.搜索旋转排序数组No.335.寻找旋转排序数组中的最小值No.153 1.搜索插入位置No.35 class Solution {public int searchInsert(int[] nums, int target) {int l 0;int r n…...
解决git clone时报错“authentication failed for huggingface repository”
问题1: 已经获取了模型的授权,但是git clone时,弹出弹窗 输入huggingface的用户名和密码后,报错如下 解决方式1: 阅读红框标注的说明,“password authentication in git is no longer supported.”&#…...
力扣-图论-16【算法学习day.66】
前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向和记录学习过程(例如想要掌握基础用法,该刷哪些题?)我的解析也不会做的非常详细,只会提供思路和一些关键点,力扣上的大佬们的题解质量是非…...
【异常】GL-SFT1200路由器中继模式,TL-CPE1300D无法搜寻5G网问题分析
【异常】GL-SFT1200路由器中继模式,TL-CPE1300D无法搜寻5G网问题 情况实验结论情况 在用GL-SFT1200路由器切换中继模式时,由于web密码忘却,需要重置,但根据官网使用手册,或者对应的中文版手册,重置失败。通过跟商家联系,进行uboot刷机,提供了指导文档,尝试后刷机成功…...
LeetCode 热题 100_K 个一组翻转链表(31_25_困难_C++)(四指针法)
LeetCode 热题 100_K 个一组翻转链表(31_25) 题目描述:输入输出样例:题解:解题思路:思路一(四指针法): 代码实现代码实现(思路一(四指针法&#x…...
【LeetCode】35.搜索插入位置
目录 LeetCode35.搜索插入位置题解解题思路code1 暴力解法2 二分查找什么是二分查找?二分查找的原理二分查找图解二分查找的优缺点……更新中 LeetCode35.搜索插入位置题解 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如…...
拿到小米 Offer,却迷茫了。。
大家好,我是程序员鱼皮,12 月了,很多小伙伴也拿到了秋招的 Offer(没拿到也不要灰心),但即使拿到 Offer,可能还会有一些其他的顾虑。今天分享我们编程导航一位鱼友的提问,给大家作为学…...
redis集群 服务器更换ip,怎么办,怎么更换redis集群的ip
redis集群 服务器更换ip,怎么办,怎么更换redis集群的ip 1、安装redis三主三从集群2、正常状态的redis集群3、更改redis集群服务器的ip 重启服务器 集群会down4、更改redis集群服务器的ip 重启服务器 集群down的原因5、更改redis集群服务器的ip后…...
运行 Mongodb Server
如何使用 mongod 命令通过配置文件启动 MongoDB Server 适用于通过 Homebrew 安装的 MongoDB Server 如果您的 MongoDB Server 是通过 Homebrew 安装的,则安装过程中会自动创建必要的文件夹和配置文件(如 mongod.conf)。您可以直接使用以下…...
“年轻科技旗舰”爱玛A7 Plus正式发布,全国售价4999元
12月18日,备受行业瞩目的“A7上场 一路超神”爱玛旗舰新品发布会在爱玛台州智造工厂盛大举行。 作为年末“压轴产品”的“两轮豪华轿跑”爱玛A7Plus重磅上场,以“快、稳、帅、炫、智、爽”六大超神技惊艳四座,不仅践行了爱玛科技的精品战略&…...
深入探索 C++ 编程技巧:从案例中学习高效实践
深入探索 C 编程技巧:从案例中学习高效实践 C 是一门功能强大且灵活的编程语言,被广泛应用于系统开发、高性能计算、游戏引擎等领域。然而,初学者和有经验的开发者常常会在代码优化、设计模式和语言特性中面临挑战。这篇文章将通过实际案例&…...
鸿蒙操作系统简介
华为鸿蒙系统(HUAWEI HarmonyOS),是华为公司于2019年8月9日在东莞举行的华为开发者大会(HDC.2019)上正式发布的面向全场景的分布式操作系统,可以创造一个超级虚拟终端互联的世界,将人、设备、场…...
LabVIEW起落架震台检测
在现代飞机制造与维护过程中,起落架的性能测试是保障飞机安全的重要环节。通过LabVIEW开发的起落架小落震台检测系统,通过模拟飞机着陆过程,准确捕捉起落架在着陆时承受的各种动力学特性和应力响应,有效提升起落架设计的精度与可靠…...
git remote -v(--verbose)显示你的 Git 仓库配置的远程仓库的详细信息
git remote -v 是一个 Git 命令,用于显示你的 Git 仓库配置的远程仓库的详细信息。 当你执行 git remote -v 命令时,你会看到类似以下的输出: origin https://github.com/your-username/your-repo.git (fetch) origin https://github.com…...
Java基础知识(四) -- 面向对象(中)
1.包 1.3.1 包的作用 (1)可以避免类重名:有了包之后,类的全名称就变为:包.类名【便于使用】(2)分类组织管理众多的类【便于管理类】(3)可以控制某些类型或成员的可见范…...
RAG开发中,如何用Milvus 2.5 BM25算法实现混合搜索
01. 背景 混合搜索(Hybrid Search)作为RAG应用中Retrieve重要的一环,通常指的是将向量搜索与基于关键词的搜索(全文检索)相结合,并使用RRF算法合并、并重排两种不同检索的结果,最终来提高数据的召回率。全文检索与语义…...
RadiAnt DICOM - 基本主题 :从 PACS 服务器打开研究
正版序列号获取:https://r-g.io/42ZopE RadiAnt DICOM Viewer PACS 客户端功能允许您从 PACS 主机(图片存档和通信系统)搜索和下载研究。 在开始之前,您需要确保您的 PACS 服务器和 RadiAnt 已正确配置。有关配置说明,…...
使用 CFD 加强水资源管理:全面概述
探索 CFD(计算流体动力学)在增强保护人类健康的土木和水利工程实践方面的重大贡献。 挑战 水资源管理是指规划、开发、分配和管理水资源最佳利用的做法。它包括广泛的活动,旨在确保水得到有效和可持续的利用,以满足各种需求&…...
AMS1117芯片驱动电路·降压芯片的驱动电路详解
编写不易,仅供学习,请勿搬运,感谢理解 AMS1117常见封装 很常用的一种LDO降压芯片,LDO(Low Dropout Regulator)降压芯片是线性稳压器,这种IC因为内部集成的不是开关电路,只能将输入与输出的电压差值通过内部…...
贪心算法 part01
class Solution { public:int maxSubArray(vector<int>& nums) {int result INT32_MIN;int count 0;for (int i 0; i < nums.size(); i) {count nums[i];if (count > result) { // 取区间累计的最大值(相当于不断确定最大子序终止位置ÿ…...
新能源汽车充电需求攀升,智慧移动充电服务有哪些实际应用场景?
在新能源汽车行业迅猛发展的今天,智慧充电桩作为支持这一变革的关键基础设施,正在多个实际应用场景中发挥着重要作用。从公共停车场到高速公路服务区,从企业园区到住宅小区,智慧充电桩不仅提供了便捷的充电服务,还通过…...
随机森林算法原理
随机森林算法原理 算法流程随机森林的生成随机森林的预测 算法总结随机森林的优点随机森林的缺点 算法流程 随机森林的生成 输入训练数据 D,样本个数为 m ,待学习的决策树数量为 T。 对于 t 1,2,…,T,从 D 中有放回地采样 m 次,…...
java中sha256和md5某个字符串实例代码
在Java中,可以使用 java.security.MessageDigest 类来计算字符串的 SHA-256 和 MD5 哈希值。以下是如何为给定的字符串生成这两种哈希值的实例代码。 生成SHA-256和MD5哈希值的示例代码 Java 深色版本 import java.security.MessageDigest; import java.security.N…...
thinkphp8自带分页bootstrap
tp8引用的是bootstrap3.4.1这个版本; 前端结构: <ul class"pagination"><li><a href"/index.php?page4"></a></li><li><a href"/index.php?page1">1</a></li>…...
C++算法第九天
本篇文章我们继续学习c算法 目录 第一题 题目链接 题目展示 代码原理 暴力解法 二分解法 代码编写 第二题 题目链接 题目展示 代码原理 代码编写 重点回顾 朴素二分 非朴素二分 重点一 重点二 重点三 第一题 题目链接 153. 寻找旋转排序数组中的最小值 - 力…...
ASRPRO学习笔记一之语音模型位置和语音替换
一、语音替换的步骤 1、扬声器录音 打开GoldWave,点击工具栏中的蓝色控制属性按钮,点击设备,选择扬声器,点击ok。打开电脑上的网易云音乐,点击红色的录制按钮,开始录制音乐,在网易云音乐上点击播放音乐,录…...
QT编译opencv
一.QT5.12编译 1.QT环境 QT5.12 Qt Creator 12.0.2 2.OpenCV文件 因为QT5.12版本qt最后支持到2021.12月,所以这里选择的opencv版本为2021.4月发布的opencv-3.4.16版本 官网下载地址:https://opencv.org/releases/ 最新版本:opencv-3.4.16.…...
[笔记]关于Qt的nativeEvent事件无法接收window消息的Bug
1.nativeEvent事件无法接收window消息 此处不是nativeEvent不能接收,是possmessage一定要写对发送的软件名称,这个名称在Qt中是主界面类的名称,就是主界面UI的名称,而不是rc文件中定义的名称。 所以在FindWindow函数获取目标窗口…...
基于深度学习的猫狗识别系统【深度学习课设】
🏆 作者简介:席万里 ⚡ 个人网站:https://dahua.bloggo.chat/ ✍️ 一名后端开发小趴菜,同时略懂Vue与React前端技术,也了解一点微信小程序开发。 🍻 对计算机充满兴趣,愿意并且希望学习更多的技…...
Java性能调优 - JVM性能监测及调优
JVM 内存模型概述 堆 堆是JVM内存中最大的一块内存空间,该内存被所有线程共享,几乎所有对象和数组都被分配到了堆内存中。堆被划分为新生代和老年代,新生代又被进一步划分为Eden和Survivor区,最后Survivor由From Survivor和To Su…...
[代码随想录21二叉树]二叉树的修改和改造,修剪二叉树,将有序数组转为二叉搜索树
前言 二叉树章节最后的题目了,就是对搜索二叉树的改造, 题目链接 669. 修剪二叉搜索树 - 力扣(LeetCode) 108. 将有序数组转换为二叉搜索树 - 力扣(LeetCode) 一、修剪二叉搜索树 思路:等会…...
C# OpenCV机器视觉:图像平滑
在一个寒冷的冬日,阿强窝在家里的沙发上,裹着厚厚的毛毯,手里捧着一杯热巧克力。他的朋友们约他一起去滑雪,但阿强却更喜欢待在温暖的家中,享受这份宁静。突然,他的手机响了,是朋友们发来的滑雪…...
Dubbo 3.x源码(26)—Dubbo服务引用源码(9)应用级服务发现订阅refreshServiceDiscoveryInvoker
基于Dubbo 3.1,详细介绍了Dubbo服务的发布与引用的源码。 此前我们学习了MigrationRuleHandler这个处理器,它用于通过动态更改规则来控制迁移行为。MigrationRuleListener的onrefer方法是Dubbo2.x 接口级服务发现与Dubbo3.x应用级服务发现之间迁移的关键…...
java client http请求 返回数据 实时循环监听 url 中资源是否生成
1、php 中 执行 exec 调用操作系统 命令行 执行 以下 java 代码 生成 的jar 2、php 执行命令是 以上1 需要命令行 输入 参数 taskid 3、实现实时监听 MP3 url 是否生成 4、 package com.example.filedemo.controller;import java.io.BufferedReader; import java.io.InputStre…...
ONES 功能上新|ONES Copilot、ONES Wiki 新功能一览
ONES Copilot 可基于工作项的标题、描述、属性信息,对工作项产生的动态和评论生成总结。 针对不同类型的工作项,总结输出的内容有对应的侧重点。 应用场景: 在一些流程步骤复杂、上下游参与成员角色丰富的场景中,工作项动态往往会…...
【自适应】postcss-pxtorem适配Web端页面
在进行页面开发时,自适应设计是一个关键的考虑因素。为了实现这一点,postcss-pxtorem是一个非常有用的工具,它可以将CSS中的px单位转换为rem单位,从而实现基于根元素字体大小的自适应布局。下面介绍一下在项目中如何引入并配置pos…...
BOE(京东方)“向新2025”年终媒体智享会首站落地上海 六大维度创新开启产业发展新篇章
12月17日,BOE(京东方)以“向新2025”为主题的年终媒体智享会在上海启动。正值BOE(京东方)新三十年的开局之年,活动全面回顾了2024年BOE(京东方)在各领域所取得的领先成果,深度解读了六大维度的“向新”发展格局,同时详细剖析了BOE(京东方)在智能制造领域的领先实践。BOE(京东方…...
Moretl安全日志采集工具
永久免费: 至Gitee下载 使用教程: Moretl使用说明 使用咨询: 用途 定时全量或增量采集工控机,电脑文件或日志. 优势 开箱即用: 解压直接运行.不需额外下载.管理设备: 后台统一管理客户端.无人值守: 客户端自启动,自更新.稳定安全: 架构简单,兼容性好,通过授权控制访问. 架…...
LabVIEW农机自主导航监控系统
随着现代农业技术的快速发展,自主导航农机的需求日益增加,提高作业效率和减少劳动成本成为农业现代化的关键目标。本文介绍了一个基于LabVIEW的农机自主导航监控系统的开发案例,该系统通过先进的传感器与控制技术,实现农机在田间作…...
ChatGPT重大更新:新增实时搜索和高级语音
12月17日消息,据报道,OpenAI开启了第八天技术分享直播,对ChatGPT搜索功能进行了大量更新。 此次ChatGPT新增的功能亮点纷呈。其中,实时搜索功能尤为引人注目。OpenAI对搜索算法进行了深度优化,使得用户提出问题后&…...
爬虫基础学习
爬虫概念与工作原理 爬虫是什么:爬虫(Web Scraping)是自动化地访问网站并提取数据的技术。它模拟用户浏览器的行为,通过HTTP请求访问网页,解析HTML文档并提取有用信息。 爬虫的基本工作流程: 发送HTTP请求…...
一般行业安全管理人员考试题库分享
1.在高速运转的机械飞轮外部安装防护罩,属于(B)安全技术措施。 A.限制能量 B.隔离 C.故障设计 D.设置薄弱环节 2.生产经营单位的(B)是本单位安全生产的第一责任人,对落实本单位安全生产主体责任全面负责,具体履行安全生产管理职责。 A.全员 B…...
递归问题(c++)
递归设计思路 数列递归 : 如果一个数列的项与项之间存在关联性,那么可以使用递归实现 ; 原理 : 如果一个函数可以求A(n),那么该函数就可以求A(n-1),就形成了递归调用 ; 注意: 一般起始项是不需要求解的,是已知条件 这就是一个典型…...
企业数字化转型规划“秘籍”全解析
一、规划前奏:明确目标与洞察现状 (一)描绘数字化转型愿景 数字化转型愿景是工程设计总承包企业未来发展的蓝图,是企业数字化征程的指引。它不仅涉及技术更新,更是企业战略、运营模式和组织文化的深度重塑。企业需确保…...
达梦8-达梦数据的示例用户和表
1、示例库说明: 创建达梦数据的示例用户和表,导入测试数据。 在完成达梦数据库的安装之后,在/opt/dmdbms/samples/instance_script目录下有用于创建示例用户的SQL文件。samples目录前的路径根据实际安装情况进行修改,本文将达梦…...
day08-别名-重定向-去重排序等
1.重复用touch命令创建同一份文件,会修改文件的时间戳。 alias命令: 别名 查看已有别名:alias [rootoldboy ~]# alias alias cpcp -i alias egrepegrep --colorauto alias fgrepfgrep --colorauto alias grepgrep --colorauto alias l.ls…...
如何在 .NET Core 中轻松实现异步编程并提升性能
目录 初识异步编程 与多线程关系 异步编程操作 初识异步编程 异步编程:是指在执行某些任务时程序可以在等待某个操作完成的过程中继续执行其他任务,而不是阻塞当前线程,这在处理I/O密集型操作(如文件读取、数据库查询、网络请求等)时尤为重…...
makefile文件
简介: 自动化编译:只需要一个make命令,整个工程自动编译 提高编译效率:再次编译时,只编译修改的文件(查看时间戳,根据修改文件的时间判断文件是否被修改) 基本语法: …...
MybatisPlus使用LambdaQueryWrapper更新时 int默认值问题
问题: User user new User();user.setBalance(1000);QueryWrapper<User> queryWrapper new QueryWrapper<>();queryWrapper.eq("username","Jack");userMapper.update(user, queryWrapper);通过用户名,更新金额&…...