Vue前端设计模式

文章目录

  • 一、什么是设计模式?
  • 二、设计几个原则
  • 三、常见的设计模式及实际案例
    • 3.1、单例模式
      • 3.1.1、`Element UI`
      • 3.1.2、`Vuex`
    • 3.2、工厂模式
      • 3.2.1、`VNode`
      • 3.2.2、`vue-route`
    • 3.3、策略模式
      • 3.3.1、表格 `formatter`
      • 3.3.2、表单验证
    • 3.4、代理模式
      • 3.4.1、拦截器
      • 3.4.2、前端框架的数据响应式化
    • 3.5、适配器模式
      • 3.5.1、`Vue` 计算属性
      • 3.5.2、源码中的适配器模式
    • 3.6、观察者模式/发布-订阅模式
      • 3.6.1、什么是观察者模式?
      • 3.6.2、什么是发布-订阅模式?
      • 3.6.3、`EventBus`
        • 3.6.3.1、创建事件中心管理组件之间的通信
        • 3.6.3.2、发送事件
        • 3.6.3.3、接收事件
      • 3.6.4、`Vue`源码
  • 四、最后

一、什么是设计模式?

设计模式是一套被反复使用、多数人知晓、经过分类编目的、代码设计经验的总结。它是为了可重用代码,让代码更容易的被他人理解并保证代码的可靠性。

设计模式实际上是“拿来主义”在软件领域的贯彻实践,它是一套现成的工具,拿来即用。下面来看一下设计模式的设计原则。

二、设计几个原则

单一职责原则、开放封闭原则、里式替换原则、接口隔离原则 、依赖反转原则 、最少知识原则。

下面我们一起来看看几种在前端领域常见的设计模式:

单例模式、工厂模式、策略模式、代理模式、适配器模式、观察者模式/发布-订阅模式

三、常见的设计模式及实际案例

3.1、单例模式

单例模式 (Singleton Pattern)又称为单体模式,保证一个类只有一个实例,并提供一个访问它的全局访问点。也就是说,第二次使用同一个类创建新对象的时候,应该得到与第一次创建的对象完全相同的对象。

3.1.1、Element UI

Element UI是使用Vue开发的一个前端UI框架。ElementUI 中的全屏 Loading 蒙层调用有两种形式:

指令形式:Vue.use(Nonradioactive)

服务形式:Vue.prototype.$loading = service

指令形式注册的使用方式 :

<div :v-loading.fullscreen="true">...</div>

服务形式注册的使用方式 :

this.$loading({ fullscreen: true })

用服务方式使用全屏 Loading 是单例的,即在前一个全屏 Loading 关闭前再次调用全屏 Loading,并不会创建一个新的 Loading 实例,而是返回现有全屏 Loading 的实例。

下面是 ElementUI 实现全屏 Loading 的源码:

import Vue from 'vue'
import loadingVue from './loading.vue'
const LoadingConstructor = Vue.extend(loadingVue)
let fullscreenLoading
const Loading = (options = {}) => {if (options.fullscreen && fullscreenLoading) {return fullscreenLoading}let instance = new LoadingConstructor({el: document.createElement('div'),data: options})if (options.fullscreen) {fullscreenLoading = instance}return instance
}
export default Loading

这里的单例是 fullscreenLoading,是存放在闭包中的,如果用户传的 optionsfullscreentrue 且已经创建了单例,则直接返回之前创建的单例,如果之前没有创建过,则创建单例并赋值给闭包中的 fullscreenLoading 后返回新创建的单例实例。

3.1.2、Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。Vuex,它们都实现了一个全局的 Store 用于存储应用的所有状态。这个 Store 的实现,正是单例模式的典型应用。
Vuex 使用单一状态树,用一个对象就包含了全部的应用层级状态。至此它便作为一个唯一数据源 (SSOT)而存在。这也意味着,每个应用将仅仅包含一个 store 实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。

// 安装vuex插件
Vue.use(Vuex)
// 将store注入到Vue实例中
new Vue({el: '#app',store
})

通过调用Vue.use()方法,安装了 Vuex 插件。Vuex 插件是一个对象,它在内部实现了一个 install 方法,这个方法会在插件安装时被调用,从而把 Store 注入到Vue实例里去。也就是说每 install 一次,都会尝试给 Vue 实例注入一个 Store

let Vue // 这个Vue的作用和楼上的instance作用一样
...
export function install (_Vue) {// 判断传入的Vue实例对象是否已经被install过Vuex插件(是否有了唯一的state)if (Vue && _Vue === Vue) {if (process.env.NODE_ENV !== 'production') {console.error('[vuex] already installed. Vue.use(Vuex) should be called only once.')}return}// 若没有,则为这个Vue实例对象install一个唯一的VuexVue = _Vue// 将Vuex的初始化逻辑写进Vue的钩子函数里applyMixin(Vue)
}

可以保证一个 Vue 实例(即一个 Vue 应用)只会被 install 一次 Vuex 插件,所以每个 Vue 实例只会拥有一个全局的 Store

3.2、工厂模式

工厂模式就是根据不用的输入返回不同的实例,一般用来创建同一类对象,它的主要思想就是将对象的创建与对象的实现分离。
在创建对象时,不暴露具体的逻辑,而是将逻辑封装在函数中,那么这个函数就可以被视为一个工厂。工厂模式根据抽象程度的不同可以分为:简单工厂、工厂方法、抽象工厂。

3.2.1、VNode

和原生的 document.createElement 类似,Vue 这种具有虚拟 DOM 树(Virtual Dom Tree)机制的框架在生成虚拟 DOM 的时候,提供了 createElement 方法用来生成 VNode,用来作为真实 DOM 节点的映射:

createElement('h3', { class: 'main-title' }, [createElement('img', { class: 'avatar', attrs: { src: '../avatar.jpg' } }),createElement('p', { class: 'user-desc' }, 'hello world')
])

createElement 函数结构大概如下:

class Vnode (tag, data, children) { ... }
function createElement(tag, data, children) {return new Vnode(tag, data, children)
}

3.2.2、vue-route

Vue在路由创建模式中,也多次用到了工厂模式:

export default class VueRouter {constructor(options) {this.mode = mode    // 路由模式switch (mode) {           // 简单工厂case 'history':       // history 方式this.history = new HTML5History(this, options.base)breakcase 'hash':          // hash 方式this.history = new HashHistory(this, options.base, this.fallback)breakcase 'abstract':      // abstract 方式this.history = new AbstractHistory(this, options.base)breakdefault:// ... 初始化失败报错}}
}

mode 是路由创建的模式,这里有三种 HistoryHashAbstract,其中,HistoryH5 的路由方式,Hash 是路由中带 # 的路由方式,Abstract 代表非浏览器环境中路由方式,比如 Nodeweex 等;this.history 用来保存路由实例,vue-router 中使用了工厂模式的思想来获得响应路由控制类的实例。

3.3、策略模式

策略模式 (Strategy Pattern)又称政策模式,其定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换。封装的策略算法一般是独立的,策略模式根据输入来调整采用哪个算法。关键是策略的实现和使用分离。

3.3.1、表格 formatter

Element UI 的表格控件的 Column 接受一个 formatter 参数,用来格式化内容,其类型为函数,并且还可以接受几个特定参数,像这样:Function(row, column, cellValue, index)

以文件大小转化为例,后端经常会直接传 bit 单位的文件大小,那么前端需要根据后端的数据,根据需求转化为自己需要的单位的文件大小,比如 KB/MB

首先实现文件计算的算法:

export const StrategyMap = {// Strategy 1: 将文件大小(bit)转化为 KB bitToKB: val => {const num = Number(val)return isNaN(num) ? val : (num / 1024).toFixed(0) + 'KB'},// Strategy 2: 将文件大小(bit)转化为 MB bitToMB: val => {const num = Number(val)return isNaN(num) ? val : (num / 1024 / 1024).toFixed(1) + 'MB'}
}
// Context: 生成el表单 formatter 
const strategyContext = function(type, rowKey){ return function(row, column, cellValue, index){StrategyMap[type](row[rowKey])}
}
export default strategyContext

在组件中直接使用:

<template><el-table :data="tableData"><el-table-column prop="date" label="日期"></el-table-column><el-table-column prop="name" label="文件名"></el-table-column><!-- 直接调用 strategyContext --><el-table-column prop="sizeKb" label="文件大小(KB)":formatter='strategyContext("bitToKB", "sizeKb")'></el-table-column><el-table-column prop="sizeMb" label="附件大小(MB)":formatter='strategyContext("bitToMB", "sizeMb")'></el-table-column></el-table>
</template>
<script type='text/javascript'>import strategyContext from './strategyContext.js'export default {name: 'ElTableDemo',data() {return {strategyContext,tableData: [{ date: '2019-05-02', name: '文件1', sizeKb: 1234, sizeMb: 1234426 },{ date: '2019-05-04', name: '文件2', sizeKb: 4213, sizeMb: 8636152 }]}}}
</script>
<style scoped></style>

运行结果如下图:

3.3.2、表单验证

除了表格中的 formatter 之外,策略模式也经常用在表单验证的场景。Element UIForm 表单 具有表单验证功能,用来校验用户输入的表单内容。实际需求中表单验证项一般会比较复杂,所以需要给每个表单项增加 validator 自定义校验方法。

实现通用的表单验证方法:

// src/utils/validates.js
// 姓名校验 由2-10位汉字组成 
export function validateUsername(str) {const reg = /^[\u4e00-\u9fa5]{2,10}$/return reg.test(str)
}
// 手机号校验 由以1开头的11位数字组成  
export function validateMobile(str) {const reg = /^1\d{10}$/return reg.test(str)
}
// 邮箱校验 
export function validateEmail(str) {const reg = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/return reg.test(str)
}

增加一个柯里化方法,用来生成表单验证函数:

// src/utils/index.js
import * as Validates from './validates.js'
// 生成表格自定义校验函数 
export const formValidateGene = (key, msg) => (rule, value, cb) => {if (Validates[key](value)) {cb()} else {cb(new Error(msg))}
}

具体使用:

<template><el-form ref="ruleForm"label-width="100px"class="demo-ruleForm":rules="rules":model="ruleForm"><el-form-item label="用户名" prop="username"><el-input v-model="ruleForm.username"></el-input></el-form-item><el-form-item label="手机号" prop="mobile"><el-input v-model="ruleForm.mobile"></el-input></el-form-item><el-form-item label="邮箱" prop="email"><el-input v-model="ruleForm.email"></el-input></el-form-item></el-form>
</template>
<script type='text/javascript'>import * as Utils from '../utils'export default {name: 'ElTableDemo',data() {return {ruleForm: { pass: '', checkPass: '', age: '' },rules: {username: [{validator: Utils.formValidateGene('validateUsername', '姓名由2-10位汉字组成'),trigger: 'blur'}],mobile: [{validator: Utils.formValidateGene('validateMobile', '手机号由以1开头的11位数字组成'),trigger: 'blur'}],email: [{validator: Utils.formValidateGene('validateEmail', '不是正确的邮箱格式'),trigger: 'blur'}]}}}}
</script>

效果如图:

3.4、代理模式

代理模式 (Proxy Pattern)又称委托模式,它为目标对象创造了一个代理对象,以控制对目标对象的访问。

代理模式把代理对象插入到访问者和目标对象之间,从而为访问者对目标对象的访问引入一定的间接性。正是这种间接性,给了代理对象很多操作空间,比如在调用目标对象前和调用后进行一些预操作和后操作,从而实现新的功能或者扩展目标的功能。

3.4.1、拦截器

在项目中经常使用 Axios 的实例来进行 HTTP 的请求,使用拦截器 interceptor 可以提前对 request 请求和 response 返回进行一些预处理,比如:

1、request 请求头的设置,和 Cookie 信息的设置;
2、权限信息的预处理,常见的比如验权操作或者 Token 验证;
3、数据格式的格式化,比如对组件绑定的 Date 类型的数据在请求前进行一些格式约定好的序列化操作;
4、空字段的格式预处理,根据后端进行一些过滤操作;
5、response 的一些通用报错处理,比如使用 Message 控件抛出错误;

除了 HTTP 相关的拦截器之外,还有路由跳转的拦截器,可以进行一些路由跳转的预处理等操作。

3.4.2、前端框架的数据响应式化

Vue 2.x 中通过 Object.defineProperty 来劫持各个属性的 setter/getter,在数据变动时,通过发布-订阅模式发布消息给订阅者,触发相应的监听回调,从而实现数据的响应式化,也就是数据到视图的双向绑定。

为什么 Vue 2.x3.x 要从 Object.defineProperty 改用 Proxy 呢,是因为前者的一些局限性,导致的以下缺陷:

1、无法监听利用索引直接设置数组的一个项,例如:vm.items[indexOfItem] = newValue
2、无法监听数组的长度的修改,例如:vm.items.length = newLength
3、无法监听 ES6SetWeakSetMapWeakMap 的变化;
4、无法监听 Class 类型的数据;
5、无法监听对象属性的新加或者删除;

3.5、适配器模式

适配器模式(Adapter Pattern)又称包装器模式,将一个类(对象)的接口(方法、属性)转化为用户需要的另一个接口,解决类(对象)之间接口不兼容的问题。

主要功能是进行转换匹配,目的是复用已有的功能,而不是来实现新的接口。也就是说,访问者需要的功能应该是已经实现好了的,不需要适配器模式来实现,适配器模式主要是负责把不兼容的接口转换成访问者期望的格式而已。

3.5.1、Vue 计算属性

Vue 中的计算属性也是一个适配器模式的实例,以官网的例子为例:

<template><div id="example"><p>Original message: "{{ message }}"</p>  <!-- Hello --><p>Computed reversed message: "{{ reversedMessage }}"</p>  <!-- olleH --></div>
</template>
<script type='text/javascript'>export default {name: 'demo',data() {return {message: 'Hello'}},computed: {reversedMessage: function() {return this.message.split('').reverse().join('')}}}
</script>

对原有数据并没有改变,只改变了原有数据的表现形式。

3.5.2、源码中的适配器模式

Axios 的用来发送请求的 adapter 本质上是封装浏览器提供的 API XMLHttpRequest

module.exports = function xhrAdapter(config) {return new Promise(function dispatchXhrRequest(resolve, reject) {var requestData = config.datavar requestHeaders = config.headersvar request = new XMLHttpRequest()// 初始化一个请求request.open(config.method.toUpperCase(),buildURL(config.url, config.params, config.paramsSerializer), true)// 设置最大超时时间request.timeout = config.timeout// readyState 属性发生变化时的回调request.onreadystatechange = function handleLoad() { ... }// 浏览器请求退出时的回调request.onabort = function handleAbort() { ... }// 当请求报错时的回调request.onerror = function handleError() { ... }// 当请求超时调用的回调request.ontimeout = function handleTimeout() { ... }// 设置HTTP请求头的值if ('setRequestHeader' in request) {request.setRequestHeader(key, val)}// 跨域的请求是否应该使用证书if (config.withCredentials) {request.withCredentials = true}// 响应类型if (config.responseType) {request.responseType = config.responseType}// 发送请求request.send(requestData)})
}

这个模块主要是对请求头、请求配置和一些回调的设置,并没有对原生的 API 有改动,所以也可以在其他地方正常使用。这个适配器可以看作是对 XMLHttpRequest 的适配,是用户对 Axios 调用层到原生 XMLHttpRequest 这个 API 之间的适配层。

3.6、观察者模式/发布-订阅模式

3.6.1、什么是观察者模式?

观察者模式(Observer Pattern)定义了一种一对多的关系,让多个订阅者对象同时监听某一个发布者,或者叫主题对象,这个主题对象的状态发生变化时就会通知所有订阅自己的订阅者对象,使得它们能够自动更新自己。

3.6.2、什么是发布-订阅模式?

其实它是发布订阅模式的一个别名,但两者又有所不同。这个别名非常形象地诠释了观察者模式里两个核心的角色要素——发布者和订阅者。

观察者模式是由具体目标调度的,而发布-订阅模式是统一由调度中心调的

3.6.3、EventBus

Vue中有一套事件机制,其中一个用法是 EventBus。可以使用 EventBus 来解决组件间的数据通信问题。

3.6.3.1、创建事件中心管理组件之间的通信
// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()
3.6.3.2、发送事件
<template><div><first-com></first-com><second-com></second-com></div>
</template>
<script>
import firstCom from './firstCom.vue'
import secondCom from './secondCom.vue'
export default {components: { firstCom, secondCom }
}
</script>

firstCom组件中发送事件:

<template><div><button @click="add">加法</button>    </div>
</template>
<script>
import {EventBus} from './event-bus.js' // 引入事件中心
export default {data(){return{num:0}},methods:{add(){EventBus.$emit('addition', {num:this.num++})}}
}
</script>
3.6.3.3、接收事件

secondCom组件中发送事件:

<template><div>求和: {{count}}</div>
</template>
<script>
import { EventBus } from './event-bus.js'
export default {data() {return {count: 0}},mounted() {EventBus.$on('addition', param => {this.count = this.count + param.num;})}
}
</script>

3.6.4、Vue源码

发布-订阅模式在源码中应用很多,比如双向绑定机制的场景

响应式化大致就是使用 Object.defineProperty 把数据转为 getter/setter,并为每个数据添加一个订阅者列表的过程。这个列表是 getter 闭包中的属性,将会记录所有依赖这个数据的组件。也就是说,响应式化后的数据相当于发布者。

每个组件都对应一个 Watcher 订阅者。当每个组件的渲染函数被执行时,都会将本组件的 Watcher 放到自己所依赖的响应式数据的订阅者列表里,这就相当于完成了订阅,一般这个过程被称为依赖收集(Dependency Collect)。
组件渲染函数执行的结果是生成虚拟 DOM 树(Virtual DOM Tree),这个树生成后将被映射为浏览器上的真实的 DOM树,也就是用户所看到的页面视图。
当响应式数据发生变化的时候,也就是触发了 setter 时,setter 会负责通知(Notify)该数据的订阅者列表里的 WatcherWatcher 会触发组件重渲染(Trigger re-render)来更新(update)视图。

// src/core/observer/index.js 响应式化过程
Object.defineProperty(obj, key, {enumerable: true,configurable: true,get: function reactiveGetter() {// ...const value = getter ? getter.call(obj) : val // 如果原本对象拥有getter方法则执行dep.depend()                     // 进行依赖收集,dep.addSubreturn value},set: function reactiveSetter(newVal) {// ...if (setter) { setter.call(obj, newVal) }    // 如果原本对象拥有setter方法则执行dep.notify()               // 如果发生变更,则通知更新}
})

四、最后

本人每篇文章都是一字一句码出来,希望对大家有所帮助,多提提意见。顺手来个三连击,点赞👍收藏💖关注✨,一起加油☕

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

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

相关文章

【分享】如何给Excel加密?码住这三种方法!

想要给Excel文件进行加密&#xff0c;方法有很多&#xff0c;今天分享三种Excel加密方法给大家。 打开密码 设置了打开密码的excel文件&#xff0c;打开文件就会提示输入密码才能打开excel文件&#xff0c;只有输入了正确的密码才能打开并且编辑文件&#xff0c;如果密码错误…

Elasticsearch常见面试题

文章目录 1.简单介绍下ES&#xff1f;2.简单介绍当前可以下载的ES稳定版本&#xff1f;3.安装ES前需要安装哪种软件&#xff1f;4.请介绍启动ES服务的步骤&#xff1f;5.ES中的倒排索引是什么&#xff1f;6. ES是如何实现master选举的&#xff1f;7. 如何解决ES集群的脑裂问题8…

高速视频采集卡设计方案:620-基于PCIe的高速视频采集卡

一、产品概述 基于PCIe的高速视频采集卡&#xff0c;通过PCIe3.0X8传输到存储计算服务器&#xff0c;实现信号的分析、存储。 北京太速科技 产品固化FPGA逻辑&#xff0c;适配视频连续采集&#xff0c;缓存容量2GB&#xff0c;开源的PCIe QT客户端软件&#xff0c…

(七)STM32 NVIC 中断、优先级管理及 AFIO 时钟的开启

目录 1. 中断相关知识简介 1.1 什么是中断 1.2 什么是内中断、外中断 1.3 什么是可屏蔽中断、不可屏蔽中断 2. CM3 内核中断介绍 2.1 F103系统异常清单 2.2 F103 外部中断清单 3. NVIC 简介 3.1 NVIC 寄存器简介 3.2 NVIC 相关寄存器的介绍 4. 中断优先级 4.1 优先…

2017年第六届数学建模国际赛小美赛B题电子邮件中的笔迹分析解题全过程文档及程序

2017年第六届数学建模国际赛小美赛 B题 电子邮件中的笔迹分析 原题再现&#xff1a; 笔迹分析是一种非常特殊的调查形式&#xff0c;用于将人们与书面证据联系起来。在法庭或刑事调查中&#xff0c;通常要求笔迹鉴定人确认笔迹样本是否来自特定的人。由于许多语言证据出现在电…

PyTorch深度学习实战(26)——卷积自编码器(Convolutional Autoencoder)

PyTorch深度学习实战&#xff08;26&#xff09;——卷积自编码器 0. 前言1. 卷积自编码器2. 使用 t-SNE 对相似图像进行分组小结系列链接 0. 前言 我们已经学习了自编码器 (AutoEncoder) 的原理&#xff0c;并使用 PyTorch 搭建了全连接自编码器&#xff0c;但我们使用的数据…

【PHP入门】2.2 流程控制

-流程控制- 流程控制&#xff1a;代码执行的方向 2.2.1控制分类 顺序结构&#xff1a;代码从上往下&#xff0c;顺序执行。&#xff08;代码执行的最基本结构&#xff09; 分支结构&#xff1a;给定一个条件&#xff0c;同时有多种可执行代码&#xff08;块&#xff09;&am…

阿里推荐 LongAdder ,不推荐 AtomicLong !

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、CAS 1.1 CAS 全称 1.2 通俗理解CAS 1.3 CAS的问题 1.4 解决 ABA 问题 二、LongAdder 2.1 什么是 LongAdder 2.2 为什么推…

用JVS低代码实现业务流程的撤回和重新开始

在当今的数字化时代&#xff0c;业务流程的效率和准确性对于企业的运营至关重要。在实际业务场景中&#xff0c;我们可能需要处理一些复杂的流程&#xff0c;例如申请审批流程、合同签订流程等。这些流程在执行过程中可能会遇到各种情况&#xff0c;例如某个审批步骤需要重新审…

❀My虚拟机上的ftp服务器搭建(centos)❀

❀My虚拟机上的ftp服务器搭建(centos)❀ 在CentOS上搭建FTP服务器可以使用vsftpd软件&#xff0c;下面是详细的搭建教程&#xff1a; ①安装vsftpd软件 在终端中输入以下命令进行安装&#xff1a; sudo yum install vsftpd ②配置vsftpd 打开vsftpd的配置文件&#xff0c;…

【深度学习】序列生成模型(五):评价方法计算实例:计算BLEU-N得分【理论到程序】

文章目录 一、BLEU-N得分&#xff08;Bilingual Evaluation Understudy&#xff09;1. 定义2. 计算N1N2BLEU-N 得分 3. 程序 给定一个生成序列“The cat sat on the mat”和两个参考序列“The cat is on the mat”“The bird sat on the bush”分别计算BLEU-N和ROUGE-N得分(N1或…

WEB渗透—PHP反序列化(六)

Web渗透—PHP反序列化 课程学习分享&#xff08;课程非本人制作&#xff0c;仅提供学习分享&#xff09; 靶场下载地址&#xff1a;GitHub - mcc0624/php_ser_Class: php反序列化靶场课程&#xff0c;基于课程制作的靶场 课程地址&#xff1a;PHP反序列化漏洞学习_哔哩…

Ubuntu 22.04 禁用(彻底移除)Snap

什么是Snaps Snaps 是 Ubuntu 的母公司 Canonical 于 2016 年 4 月发布 Ubuntu 16.04 LTS&#xff08;Long Term Support&#xff0c;长期支持版&#xff09;时引入的一种容器化的软件包格式。自 Ubuntu 16.04 LTS 起&#xff0c;Ubuntu 操作系统可以同时支持 Snap 及 Debian …

3dsmax渲染太慢,用云渲染农场多少钱?

对于许多从事计算机图形设计的创作者来说&#xff0c;渲染速度慢是一个常见问题&#xff0c;尤其是对于那些追求极致出图效果的室内设计师和建筑可视化师&#xff0c;他们通常使用3ds Max这样的工具&#xff0c;而高质量的渲染经常意味着长时间的等待。场景复杂、细节丰富&…

APView500PV电能质量在线监测装置——安科瑞 顾烊宇

概述 APView500PV电能质量在线监测装置采用了高性能多核平台和嵌入式操作系统&#xff0c;遵照IEC61000-4-30《测试和测量技术-电能质量测量方法》中规定的各电能质量指标的测量方法进行测量&#xff0c;集谐波分析、波形采样、电压暂降/暂升/中断、闪变监测、电压不平衡度监测…

CentOS操作学习(二)

上一篇学习了CentOS的常用指令CentOS指令学习-CSDN博客 现在我们接着学习 一、Vi编辑器 这是CentOS中自带的编辑器 三种模式 进入编辑模式后 i&#xff1a;在光标所在字符前开始插入a&#xff1a;在光标所在字符串后开始插入o&#xff1a;在光标所在行的下面另起一新行插入…

命令执行 [SWPUCTF 2021 新生赛]easyrce

打开题目 提示要用url传参&#xff0c;但实际是用url进行一些系统命令执行 那我们就用whoami命令来查看用户和权限 那我们直接用ls / 去查看当下根目录下有哪些文件 我们看到根目录下有flag 直接cat读取就行 知识点&#xff1a; system system是一个函数 用来运行外部的程序…

4.CentOS7开启ssh

Centos7开启ssh 通过命令查看是否安装了ssh服务 rpm -qa | grep openssh 修改主配置文件 vim /etc/ssh/sshd_config 将PermitRootLogin&#xff0c;RSAAuthentication&#xff0c;PubkeyAuthentication的设置打开 RSAAuthentication yes# 启用 RSA 认证PubkeyAuthenticatio…

19_20-Golang中的切片

**Golang **中的切片 主讲教师&#xff1a;&#xff08;大地&#xff09; 合作网站&#xff1a;www.itying.com** **&#xff08;IT 营&#xff09; 我的专栏&#xff1a;https://www.itying.com/category-79-b0.html 1、为什么要使用切片 因为数组的长度是固定的并且数组长…