Vue前端设计模式

news2024/9/21 2:32:26

文章目录

  • 一、什么是设计模式?
  • 二、设计几个原则
  • 三、常见的设计模式及实际案例
    • 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一个唯一的Vuex
  Vue = _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)
                break
            case 'hash':          // hash 方式
                this.history = new HashHistory(this, options.base, this.fallback)
                break
            case 'abstract':      // abstract 方式
                this.history = new AbstractHistory(this, options.base)
                break
            default:
                // ... 初始化失败报错
        }
    }
}

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.data
        var requestHeaders = config.headers
        
        var 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.addSub
        return value
    },
    set: function reactiveSetter(newVal) {
        // ...
        if (setter) { setter.call(obj, newVal) }    // 如果原本对象拥有setter方法则执行
        dep.notify()               // 如果发生变更,则通知更新
    }
})

四、最后

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

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

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

相关文章

考研小白助力宝典(2)

前言 考研&#xff0c;是一场耗时长久的脑力之战&#xff0c;刻苦勤奋的态度和披荆斩棘的精神外&#xff0c;往往取决于谁抓好了信息利剑&#xff01;合理得当利用好信息平台&#xff0c;就已经快人一步战胜了大部分的竞争对手了&#xff01; 目录 着重学习练习 考研相关简介 …

vscode开发python环境配置

前言 vscode作为一款好用的轻量级代码编辑器&#xff0c;不仅支持代码调试&#xff0c;而且还有丰富的插件库&#xff0c;可以说是免费好用&#xff0c;对于初学者来说用来写写python是再合适不过了。下面就推荐几款个人觉得还不错的插件&#xff0c;希望可以帮助大家更好地写…

visio绘制封闭图形并填充颜色

文章目录 一、绘制扇形二、填充颜色 一、绘制扇形 1.文件->选项->开发工具 2.使用圆形和直线绘制如图所示图形 3.选中该图形&#xff0c;选择开发工具->操作->修剪 4.拖动即为扇形。 二、填充颜色 选择开发工具-操作选项&#xff0c;并分别依次点击组合-连接-拆分…

laravel 对接支付,本地穿透问题

本地穿透有好多工具&#xff0c;参考链接&#xff1a;https://zhuanlan.zhihu.com/p/339923535 我这边是用的 NATAPP 官网&#xff1a;https://natapp.cn/ 客户端下载&#xff1a;https://natapp.cn/# NATAPP1分钟快速新手图文教程&#xff1a;https://natapp.cn/article/n…

C# NPOI导出datatable----Excel模板画图表

1、创建Excel模板 2、安装NPOI管理包 3、创建工作簿 &#xff08;XLSX和XLS步骤一样&#xff0c;以XLS为例&#xff09; IWorkbook workbook null; string time DateTime.Now.ToString("yyyyMMddHHmmss"); string excelTempPath Application.StartupPath "…

flutter开发实战-第一帧布局完成回调实现

flutter开发实战-第一帧布局完成回调实现 在开发中&#xff0c;我们有时候需要在第一帧布局完成后调用一些相关的方法。这里记录一下是实现过程。 Flutter中有多种不同的Binding&#xff0c;每种Binding都负责不同的功能。下面是Flutter中常见的Binding&#xff1a; 这里简单…

EMD、EEMD、FEEMD、CEEMD、CEEMDAN的区别、原理和Python实现(四)CEEMD

往期精彩内容: 风速预测&#xff08;一&#xff09;数据集介绍和预处理-CSDN博客 风速预测&#xff08;二&#xff09;基于Pytorch的EMD-LSTM模型-CSDN博客 风速预测&#xff08;三&#xff09;EMD-LSTM-Attention模型-CSDN博客 风速预测&#xff08;四&#xff09;基于Pyt…

25、新加坡南洋理工、新加坡国立大学提出FBCNet:完美融合FBCSP的CNN,EEG解码SOTA水准![抱歉老师,我太想进步了!]

前言&#xff1a; 阴阳差错&#xff0c;因工作需要&#xff0c;需要查阅有关如何将FBCSP融入CNN中的文献&#xff0c;查阅全网&#xff0c;发现只此一篇文章&#xff0c;心中大喜&#xff0c;心想作者哪家单位&#xff0c;读之&#xff0c;原来是自己大导&#xff08;新加坡工…

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

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

pytorch-模型预测概率值为负数

在进行ocr识别模型预测的时候&#xff0c;发现预测的结果是正确的&#xff0c;但是概率值是负数&#xff1a; net_out net(img) #torch.Size([70, 1, 41]) logit, preds net_out.max(2) #41是类别 需要对类别取最大值 preds preds.transpose(1, 0).contiguous().view(-1) …

圆通单号查询,圆通速递物流查询,将指定派件员的单号筛选出来

批量查询圆通速递单号的物流信息&#xff0c;并将指定派件员的单号筛选出来。 所需工具&#xff1a; 一个【快递批量查询高手】软件 圆通速递单号若干 操作步骤&#xff1a; 步骤1&#xff1a;运行【快递批量查询高手】软件&#xff0c;第一次使用的伙伴记得先注册&#xff…

AIGC:阿里开源大模型通义千问部署与实战

1 引言 通义千问-7B&#xff08;Qwen-7B&#xff09;是阿里云研发的通义千问大模型系列的70亿参数规模的模型。Qwen-7B是基于Transformer的大语言模型, 在超大规模的预训练数据上进行训练得到。预训练数据类型多样&#xff0c;覆盖广泛&#xff0c;包括大量网络文本、专业书籍…

JS模块化规范之CMD

JS模块化规范之CMD 模块化规范CMD&#xff08;Common Module Definition&#xff09;概念基本语法CMD实现 模块化规范 CMD&#xff08;Common Module Definition&#xff09; 概念 CommonJS module definition CMD规范专门用于浏览器端&#xff0c;模块的加载时异步的&#x…

macOS 开发 - 报错 Expected expression(空格问题)

文章目录 问题尝试解决方式 问题 一个简单的 查找沙盒内文件的代码&#xff0c;编译不通过&#xff0c;很郁闷 尝试 可以肯定 NSBundle 代码这么写没问题&#xff0c;即使重敲还是报错&#xff1b; 换个位置&#xff0c;甚至 mainBundle 都无法提示出来。 重启 Xcode 也无法…

钓鱼篇(中)

鱼竿感知 鱼竿感知系统其实非常重要&#xff0c;比如鱼儿上钩&#xff0c;你还一直弹窗&#xff0c;这样是个小白也能知道不正常。那么如何做好一个简单的感知系统呢&#xff1f;其实非常简单,这里我丢一个简单的demo,实际上它是可以写成一个框架的(这个先不考虑放出来) 这里…

5-高可用-降级

在开发高并发系统时&#xff0c;有很多手段来保护系统&#xff0c;如缓存、降级和限流等。 当访问量剧增、服务出现问题(如响应时间长或不响应)或非核心服务影响到核心流程的性能时&#xff0c;仍然需要保证服务还是可用的&#xff0c;即使是有损服务。 系统可以根据一些关键…

论文解读:On the Integration of Self-Attention and Convolution

自注意力机制与卷积结合&#xff1a;On the Integration of Self-Attention and Convolution(CVPR2022) 引言 1&#xff1a;卷积可以接受比较大的图片的&#xff0c;但自注意力机制如果图片特别大的话&#xff0c;运算规模会特别大&#xff0c;即上图中右边(卷积)会算得比较快…

c语言:求算数平均数|练习题

一、题目 输入3个数&#xff0c;求这三个数的算术平均数 二、代码图片【带注释】 三、源代码【带注释】 #include <stdio.h> #include<math.h> //输入正整数a、b、c的值&#xff0c; //求其算术平均值,并保留两个小数位输出 int pass0;//定义一个开关&#xff0c;…

《JVM由浅入深学习【一】 2023-12-19》JVM由简入深学习提升

JVM由浅入深一&#xff08;类加载&#xff09; JVM的类加载1. java运行时是什么时候被加载的&#xff1f;2. JVM类加载过程大致阶段3. 父类与子类初始化各个类型顺序4. 什么是类加载器&#xff1f;6. 双亲委派机制 JVM的类加载 1. java运行时是什么时候被加载的&#xff1f; …

win10部署安装Elasticsearch8.1.2

环境准备&#xff1a;JDk是1.8以上版本 1、官方下载Elasticsearch部署安装 访问官网,进入主页下载。 2、在下载页面&#xff0c;可以看到选择操作系统&#xff0c;选择系统后点击下载。&#xff08;我这里下载的Windows版本&#xff09; 3下载完成后&#xff0c;解压文件&am…