js文件里获取路由 vue_【源码拾遗】从vue-router看前端路由的两种实现

本文由浅入深观摩vue-router源码是如何通过hash与History interface两种方式实现前端路由,介绍了相关原理,并对比了两种方式的优缺点与注意事项。最后分析了如何实现可以直接从文件系统加载而不借助后端服务器的Vue单页应用。

随着前端应用的业务功能越来越复杂、用户对于使用体验的要求越来越高,单页应用(SPA)成为前端应用的主流形式。大型单页应用最显著特点之一就是采用前端路由系统,通过改变URL,在不重新请求页面的情况下,更新页面视图。

“更新视图但不重新请求页面”是前端路由原理的核心之一,目前在浏览器环境中这一功能的实现主要有两种方式:利用URL中的hash(“#”)

利用History interface在 HTML5中新增的方法

vue-router是Vue.js框架的路由插件,下面我们从它的源码入手,边看代码边看原理,由浅入深观摩vue-router是如何通过这两种方式实现前端路由的。

模式参数

在vue-router中是通过mode这一参数控制路由的实现模式的:

const router = new VueRouter({

mode: 'history',

routes: [...]

})

创建VueRouter的实例对象时,mode以构造函数参数的形式传入。带着问题阅读源码,我们就可以从VueRouter类的定义入手。一般插件对外暴露的类都是定义在源码src根目录下的index.js文件中,打开该文件,可以看到VueRouter类的定义,摘录与mode参数有关的部分如下:

export default class VueRouter {

mode: string; // 传入的字符串参数,指示history类别

history: HashHistory | HTML5History | AbstractHistory; // 实际起作用的对象属性,必须是以上三个类的枚举

fallback: boolean; // 如浏览器不支持,'history'模式需回滚为'hash'模式

constructor (options: RouterOptions = {}) {

let mode = options.mode || 'hash' // 默认为'hash'模式

this.fallback = mode === 'history' && !supportsPushState // 通过supportsPushState判断浏览器是否支持'history'模式

if (this.fallback) {

mode = 'hash'

}

if (!inBrowser) {

mode = 'abstract' // 不在浏览器环境下运行需强制为'abstract'模式

}

this.mode = mode

// 根据mode确定history实际的类并实例化

switch (mode) {

case 'history':

this.history = new HTML5History(this, options.base)

break

case 'hash':

this.history = new HashHistory(this, options.base, this.fallback)

break

case 'abstract':

this.history = new AbstractHistory(this, options.base)

break

default:

if (process.env.NODE_ENV !== 'production') {

assert(false, `invalid mode: ${mode}`)

}

}

}

init (app: any /* Vue component instance */) {

const history = this.history

// 根据history的类别执行相应的初始化操作和监听

if (history instanceof HTML5History) {

history.transitionTo(history.getCurrentLocation())

} else if (history instanceof HashHistory) {

const setupHashListener = () => {

history.setupListeners()

}

history.transitionTo(

history.getCurrentLocation(),

setupHashListener,

setupHashListener

)

}

history.listen(route => {

this.apps.forEach((app) => {

app._route = route

})

})

}

// VueRouter类暴露的以下方法实际是调用具体history对象的方法

push (location: RawLocation, onComplete?: Function, onAbort?: Function) {

this.history.push(location, onComplete, onAbort)

}

replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {

this.history.replace(location, onComplete, onAbort)

}

}

可以看出:

作为参数传入的字符串属性mode只是一个标记,用来指示实际起作用的对象属性history的实现类,两者对应关系如下:modehistory'history'HTML5History'hash'HashHistory'abstract'AbstractHistory

在初始化对应的history之前,会对mode做一些校验:若浏览器不支持HTML5History方式(通过supportsPushState变量判断),则mode强制设为'hash';若不是在浏览器环境下运行,则mode强制设为'abstract'

VueRouter类中的onReady(), push()等方法只是一个代理,实际是调用的具体history对象的对应方法,在init()方法中初始化时,也是根据history对象具体的类别执行不同操作

在浏览器环境下的两种方式,分别就是在HTML5History,HashHistory两个类中实现的。他们都定义在src/history文件夹下,继承自同目录下base.js文件中定义的History类。History中定义的是公用和基础的方法,直接看会一头雾水,我们先从HTML5History,HashHistory两个类中看着亲切的push(), replace()方法的说起。

HashHistory

看源码前先回顾一下原理:

hash(“#”)符号的本来作用是加在URL中指示网页中的位置:http://www.example.com/index.html#print

#符号本身以及它后面的字符称之为hash,可通过window.location.hash属性读取。它具有如下特点:hash虽然出现在URL中,但不会被包括在HTTP请求中。它是用来指导浏览器动作的,对服务器端完全无用,因此,改变hash不会重新加载页面

可以为hash的改变添加监听事件:

window.addEventListener("hashchange", funcRef, false)

每一次改变hash(window.location.hash),都会在浏览器的访问历史中增加一个记录

利用hash的以上特点,就可以来实现前端路由“更新视图但不重新请求页面”的功能了。

HashHistory.push()

我们来看HashHistory中的push()方法:

push (location: RawLocation, onComplete?: Function, onAbort?: Function) {

this.transitionTo(location, route => {

pushHash(route.fullPath)

onComplete && onComplete(route)

}, onAbort)

}

function pushHash (path) {

window.location.hash = path

}

transitionTo()方法是父类中定义的是用来处理路由变化中的基础逻辑的,push()方法最主要的是对window的hash进行了直接赋值:

window.location.hash = route.fullPath

hash的改变会自动添加到浏览器的访问历史记录中。

那么视图的更新是怎么实现的呢,我们来看父类History中transitionTo()方法的这么一段:

transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) {

const route = this.router.match(location, this.current)

this.confirmTransition(route, () => {

this.updateRoute(route)

...

})

}

updateRoute (route: Route) {

this.cb && this.cb(route)

}

listen (cb: Function) {

this.cb = cb

}

可以看到,当路由变化时,调用了History中的this.cb方法,而this.cb方法是通过History.listen(cb)进行设置的。回到VueRouter类定义中,找到了在init()方法中对其进行了设置:

init (app: any /* Vue component instance */) {

this.apps.push(app)

history.listen(route => {

this.apps.forEach((app) => {

app._route = route

})

})

}

根据注释,app为Vue组件实例,但我们知道Vue作为渐进式的前端框架,本身的组件定义中应该是没有有关路由内置属性_route,如果组件中要有这个属性,应该是在插件加载的地方,即VueRouter的install()方法中混合入Vue对象的,查看install.js源码,有如下一段:

export function install (Vue) {

Vue.mixin({

beforeCreate () {

if (isDef(this.$options.router)) {

this._router = this.$options.router

this._router.init(this)

Vue.util.defineReactive(this, '_route', this._router.history.current)

}

registerInstance(this, this)

},

})

}

通过Vue.mixin()方法,全局注册一个混合,影响注册之后所有创建的每个 Vue 实例,该混合在beforeCreate钩子中通过Vue.util.defineReactive()定义了响应式的_route属性。所谓响应式属性,即当_route值改变时,会自动调用Vue实例的render()方法,更新视图。

总结一下,从设置路由改变到视图更新的流程如下:

$router.push() --> HashHistory.push() --> History.transitionTo() --> History.updateRoute() --> {app._route = route} --> vm.render()

HashHistory.replace()

replace()方法与push()方法不同之处在于,它并不是将新路由添加到浏览器访问历史的栈顶,而是替换掉当前的路由:

replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {

this.transitionTo(location, route => {

replaceHash(route.fullPath)

onComplete && onComplete(route)

}, onAbort)

}

function replaceHash (path) {

const i = window.location.href.indexOf('#')

window.location.replace(

window.location.href.slice(0, i >= 0 ? i : 0) + '#' + path

)

}

可以看出,它与push()的实现结构上基本相似,不同点在于它不是直接对window.location.hash进行赋值,而是调用window.location.replace方法将路由进行替换。

监听地址栏

以上讨论的VueRouter.push()和VueRouter.replace()是可以在vue组件的逻辑代码中直接调用的,除此之外在浏览器中,用户还可以直接在浏览器地址栏中输入改变路由,因此VueRouter还需要能监听浏览器地址栏中路由的变化,并具有与通过代码调用相同的响应行为。在HashHistory中这一功能通过setupListeners实现:

setupListeners () {

window.addEventListener('hashchange', () => {

if (!ensureSlash()) {

return

}

this.transitionTo(getHash(), route => {

replaceHash(route.fullPath)

})

})

}

该方法设置监听了浏览器事件hashchange,调用的函数为replaceHash,即在浏览器地址栏中直接输入路由相当于代码调用了replace()方法

HTML5History

History interface是浏览器历史记录栈提供的接口,通过back(), forward(), go()等方法,我们可以读取浏览器历史记录栈的信息,进行各种跳转操作。

从HTML5开始,History interface提供了两个新的方法:pushState(), replaceState()使得我们可以对浏览器历史记录栈进行修改:

window.history.pushState(stateObject, title, URL)

window.history.replaceState(stateObject, title, URL)stateObject: 当浏览器跳转到新的状态时,将触发popState事件,该事件将携带这个stateObject参数的副本

title: 所添加记录的标题

URL: 所添加记录的URL

这两个方法有个共同的特点:当调用他们修改浏览器历史记录栈后,虽然当前URL改变了,但浏览器不会立即发送请求该URL(the browser won't attempt to load this URL after a call to pushState()),这就为单页应用前端路由“更新视图但不重新请求页面”提供了基础。

我们来看vue-router中的源码:

push (location: RawLocation, onComplete?: Function, onAbort?: Function) {

const { current: fromRoute } = this

this.transitionTo(location, route => {

pushState(cleanPath(this.base + route.fullPath))

handleScroll(this.router, route, fromRoute, false)

onComplete && onComplete(route)

}, onAbort)

}

replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {

const { current: fromRoute } = this

this.transitionTo(location, route => {

replaceState(cleanPath(this.base + route.fullPath))

handleScroll(this.router, route, fromRoute, false)

onComplete && onComplete(route)

}, onAbort)

}

// src/util/push-state.js

export function pushState (url?: string, replace?: boolean) {

saveScrollPosition()

// try...catch the pushState call to get around Safari

// DOM Exception 18 where it limits to 100 pushState calls

const history = window.history

try {

if (replace) {

history.replaceState({ key: _key }, '', url)

} else {

_key = genKey()

history.pushState({ key: _key }, '', url)

}

} catch (e) {

window.location[replace ? 'replace' : 'assign'](url)

}

}

export function replaceState (url?: string) {

pushState(url, true)

}

代码结构以及更新视图的逻辑与hash模式基本类似,只不过将对window.location.hash直接进行赋值window.location.replace()改为了调用history.pushState()和history.replaceState()方法。

在HTML5History中添加对修改浏览器地址栏URL的监听是直接在构造函数中执行的:

constructor (router: Router, base: ?string) {

window.addEventListener('popstate', e => {

const current = this.current

this.transitionTo(getLocation(this.base), route => {

if (expectScroll) {

handleScroll(router, route, current, true)

}

})

})

}

当然了HTML5History用到了HTML5的新特特性,是需要特定浏览器版本的支持的,前文已经知道,浏览器是否支持是通过变量supportsPushState来检查的:

// src/util/push-state.js

export const supportsPushState = inBrowser && (function () {

const ua = window.navigator.userAgent

if (

(ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&

ua.indexOf('Mobile Safari') !== -1 &&

ua.indexOf('Chrome') === -1 &&

ua.indexOf('Windows Phone') === -1

) {

return false

}

return window.history && 'pushState' in window.history

})()

以上就是hash模式与history模式源码的导读,这两种模式都是通过浏览器接口实现的,除此之外vue-router还为非浏览器环境准备了一个abstract模式,其原理为用一个数组stack模拟出浏览器历史记录栈的功能。当然,以上只是一些核心逻辑,为保证系统的鲁棒性源码中还有大量的辅助逻辑,也很值得学习。此外在vue-router中还有路由匹配、router-view视图组件等重要部分,关于整体源码的阅读推荐滴滴前端的这篇文章

两种模式比较

在一般的需求场景中,hash模式与history模式是差不多的,但几乎所有的文章都推荐使用history模式,理由竟然是:"#" 符号太丑...0_0 "如果不想要很丑的 hash,我们可以用路由的 history 模式 ——官方文档

当然,严谨的我们肯定不应该用颜值评价技术的好坏。根据MDN的介绍,调用history.pushState()相比于直接修改hash主要有以下优势:pushState设置的新URL可以是与当前URL同源的任意URL;而hash只可修改#后面的部分,故只可设置与当前同文档的URL

pushState设置的新URL可以与当前URL一模一样,这样也会把记录添加到栈中;而hash设置的新值必须与原来不一样才会触发记录添加到栈中

pushState通过stateObject可以添加任意类型的数据到记录中;而hash只可添加短字符串

pushState可额外设置title属性供后续使用

history模式的一个问题

我们知道对于单页应用来讲,理想的使用场景是仅在进入应用时加载index.html,后续在的网络操作通过Ajax完成,不会根据URL重新请求页面,但是难免遇到特殊情况,比如用户直接在地址栏中输入并回车,浏览器重启重新加载应用等。

hash模式仅改变hash部分的内容,而hash部分是不会包含在HTTP请求中的:

http://oursite.com/#/user/id // 如重新请求只会发送http://oursite.com/

故在hash模式下遇到根据URL请求页面的情况不会有问题。

而history模式则会将URL修改得就和正常请求后端的URL一样

http://oursite.com/user/id

在此情况下重新向后端发送请求,如后端没有配置对应/user/id的路由处理,则会返回404错误。官方推荐的解决办法是在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。同时这么做以后,服务器就不再返回 404 错误页面,因为对于所有路径都会返回 index.html 文件。为了避免这种情况,在 Vue 应用里面覆盖所有的路由情况,然后在给出一个 404 页面。或者,如果是用 Node.js 作后台,可以使用服务端的路由来匹配 URL,当没有匹配到路由的时候返回 404,从而实现 fallback。

直接加载应用文件Tip: built files are meant to be served over an HTTP server.

Opening index.html over file:// won't work.

Vue项目通过vue-cli的webpack打包完成后,命令行会有这么一段提示。通常情况,无论是开发还是线上,前端项目都是通过服务器访问,不存在 "Opening index.html over file://" ,但程序员都知道,需求和场景永远是千奇百怪的,只有你想不到的,没有产品经理想不到的。

本文写作的初衷就是遇到了这样一个问题:需要快速开发一个移动端的展示项目,决定采用WebView加载Vue单页应用的形式,但没有后端服务器提供,所以所有资源需从本地文件系统加载:

// AndroidAppWrapper

public class MainActivity extends AppCompatActivity {

private WebView webView;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

webView = new WebView(this);

webView.getSettings().setJavaScriptEnabled(true);

webView.loadUrl("file:///android_asset/index.html");

setContentView(webView);

}

@Override

public boolean onKeyDown(int keyCode, KeyEvent event) {

if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {

webView.goBack();

return true;

}

return false;

}

}

此情此景看来是必须 "Opening index.html over file://" 了,为此,我首先要进行了一些设置在项目config.js文件中将assetsPublicPath字段的值改为相对路径 './'

调整生成的static文件夹中图片等静态资源的位置与代码中的引用地址一致

这是比较明显的需要改动之处,但改完后依旧无法顺利加载,经过反复排查发现,项目在开发时,router设置为了history模式(为了美观...0_0"),当改为hash模式后就可正常加载了。

为什么会出现这种情况呢?我分析原因可能如下:

当从文件系统中直接加载index.html时,URL为:

file:///android_asset/index.html

而首页视图需匹配的路径为path: '/' :

export default new Router({

mode: 'history',

routes: [

{

path: '/',

name: 'index',

component: IndexView

}

]

})

我们先来看history模式,在HTML5History中:

ensureURL (push?: boolean) {

if (getLocation(this.base) !== this.current.fullPath) {

const current = cleanPath(this.base + this.current.fullPath)

push ? pushState(current) : replaceState(current)

}

}

export function getLocation (base: string): string {

let path = window.location.pathname

if (base && path.indexOf(base) === 0) {

path = path.slice(base.length)

}

return (path || '/') + window.location.search + window.location.hash

}

逻辑只会确保存在URL,path是通过剪切的方式直接从window.location.pathname获取到的,它的结尾是index.html,因此匹配不到 '/' ,故 "Opening index.html over file:// won't work" 。

再看hash模式,在HashHistory中:

export class HashHistory extends History {

constructor (router: Router, base: ?string, fallback: boolean) {

...

ensureSlash()

}

// this is delayed until the app mounts

// to avoid the hashchange listener being fired too early

setupListeners () {

window.addEventListener('hashchange', () => {

if (!ensureSlash()) {

return

}

...

})

}

getCurrentLocation () {

return getHash()

}

}

function ensureSlash (): boolean {

const path = getHash()

if (path.charAt(0) === '/') {

return true

}

replaceHash('/' + path)

return false

}

export function getHash (): string {

const href = window.location.href

const index = href.indexOf('#')

return index === -1 ? '' : href.slice(index + 1)

}

我们看到在代码逻辑中,多次出现一个函数ensureSlash(),当#符号后紧跟着的是'/',则返回true,否则强行插入这个'/',故我们可以看到,即使是从文件系统打开index.html,URL依旧会变为以下形式:

file:///C:/Users/dist/index.html#/

getHash()方法返回的path为 '/' ,可与首页视图的路由匹配。

故要想从文件系统直接加载Vue单页应用而不借助后端服务器,除了打包后的一些路径设置外,还需确保vue-router使用的是hash模式。

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

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

相关文章

龙武2服务器在维护,龙武5.25更新维护时间_龙武5.5更新维护详情_牛游戏网

龙武5.25日更新维护公告,相信小伙伴们也很关心更新内容,那么,让我们一起看看这次更新的内容吧!尊敬的广大玩家朋友:为保证玩家顺畅进行游戏,提高整体服务质量,给玩家提供更好的服务,…

[bzoj1036][ZJOI2008]树的统计Count

Description 一棵树上有$n$个节点,编号分别为$1$到$n$,每个节点都有一个权值$w_i$. 有三种操作: $1.CHANGE\;u\;t$:把结点$u$的权值改为$t$; $2.QMAX\;u\;v$:询问从点$u$到点$v$的路径上的节点的最大权值; $3.QSUM\;u\;v$:询问从点$u$到点$v$的路径上的节点的权值和. $P.S.$ 从…

祁飞机器人_转自祈飞:什么是智能机器人

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼智能机器人新型驱动器智能机器人除了传统的电动机驱动、液压驱动、气压驱动等方式外,由于结构及尺寸的不同,还常采用如下一些新型的驱动器。静电驱动形状记忆合金驱动压电驱动及磁致伸缩驱动。1、静电驱动器…

服务器操作系统策略,服务器操作系统策略

服务器操作系统策略 内容精选换一换Windows操作系统的云服务器由于管理员设置的策略,该磁盘处于脱机状态,提示:由于管理员设置的策略,该磁盘处于脱机状态,如图1所示。Windows操作系统SAN策略分为三种类型:O…

poj 3680 Intervals

给定N个带权的开区间&#xff0c;第i个区间覆盖区间(ai,bi)&#xff0c;权值为wi。现在要求挑出一些区间使得总权值最大&#xff0c;并且满足实轴上任意一个点被覆盖不超过K次。 1<K<N<200.1<ai<bi<100000.1<wi<100000. 最小费用最大流。 将所有区间端…

as安装过程中gradle_在安装钢结构平台过程中需要注意哪些事项?

钢制平台货架是在厂房面积有限的情况下采用货架作为阁楼支撑&#xff0c;并可以设计多层&#xff08;通常2&#xff5e;3层&#xff09;的存储货架&#xff0c;阁楼可以采用楼梯或者液压升降平台做为登高设施&#xff0c;利用金属专用楼板作为楼层区分&#xff0c;每层可以放置…

服务器的显示器设置方法,服务器的显示器设置方法

服务器的显示器设置方法 内容精选换一换远程登录Windows弹性云服务器后&#xff0c;修改分辨率设置。不同版本的Windows操作系统&#xff0c;操作略有差异&#xff0c;本节以Windows Server 2016 标准版 64bit为例&#xff0c;介绍如何修改Windows弹性云服务器的分辨率。通过VN…

Mac下svn搭建和使用方法

先安装svn服务器&#xff0c;然后执行以下步骤&#xff1a; 1.创建svn服务器库&#xff1a;svnadmin create ~/Documents/tools/svn/server/code 2.启动svn服务器&#xff1a;svnserve -d -r ~/Documents/tools/svn/server/code 3.导入数据到svn库&#xff1a;svn import ~/Doc…

rust腐竹是什么意思_学习Rust 集合与字符串

Rust 语言是一种高效、可靠的通用高级语言。其高效不仅限于开发效率&#xff0c;它的执行效率也是令人称赞的&#xff0c;是一种少有的兼顾开发效率和执行效率的语言。集合(Collection)是数据结构中最普遍的数据存放形式&#xff0c;Rust 标准库中提供了丰富的集合类型帮助开发…

java解压服务器文件夹,java获取远程服务器上的文件夹

java获取远程服务器上的文件夹 内容精选换一换安装X722板载网卡驱动软件包&#xff0c;使裸金属服务器支持在v5服务器上下发。其他类型服务器可跳过此步骤。本文以Windows Server 2016为例&#xff0c;Windows Server 2012 R2与之类似。解压缩准备工作中的“onboard_driver_win…

矩阵求多元函数的通解_Hessian矩阵

黑塞矩阵(Hessian Matrix)&#xff0c;是一个多元函数的二阶偏导数构成的方阵&#xff0c;描述了函数的局部曲率。黑塞矩阵常用于牛顿法解决优化问题&#xff0c;利用黑塞矩阵可判定多元函数的极值问题。在工程实际问题的优化设计中&#xff0c;所列的目标函数往往很复杂&#…

坦克游戏服务器未响应,《坦克世界》退出战斗 退出战斗卡死解决办法

不知道大家有没有过&#xff0c;在玩坦克世界时&#xff0c;退出战斗会有卡死的情况。小编是没有遇到过。但却看到很多游戏中的朋友反映过。下面小编为大家整理了几个关于退出战斗卡死的情况&#xff0c;以及遇到此情况的玩家的解决办法。希望能给大家带来帮助哦~玩家遇到情况解…

js中当等于最小值是让代码不执行_从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理...

前言见解有限&#xff0c;如有描述不当之处&#xff0c;请帮忙及时指出&#xff0c;如有错误&#xff0c;会及时修正。----------超长文多图预警&#xff0c;需要花费不少时间。----------如果看完本文后&#xff0c;还对进程线程傻傻分不清&#xff0c;不清楚浏览器多进程、浏…

HTML5笔记1——HTML5的发展史及标签的改变

记得第一次接触HTML5还是在《联信永益》实习那会儿&#xff08;2011&#xff09;&#xff0c;当时一个项目技术选型的时候面临两种选择&#xff0c;分别是Silverlight和HTML5&#xff0c;那是用的最新的IE浏览器版本还是IE9&#xff0c;而IE9才刚刚开始支持HTML5。后来考虑到当…

华兴数控g71外圆循环编程_数控车床加工编程典型实例分析(西门子802S数控系统)...

这是一篇带有教学色彩的习作&#xff0c;文章对数控编程的方式和步骤进行了简明的阐述&#xff0c;并针对一个典型零件的数控车削加工给出了一套程序。程序是以西门子802S数控系统为例编写的。数控机床是一种技术密集度及自动化程度很高的机电一体化加工设备&#xff0c;是综合…

4-数组、指针与字符串1.4-动态内存分配

这种在程序运行过程中申请和释放的存储单元也称为堆对象&#xff0c;申请和释放过程过程一般称为建立和删除。 1、new运算和delete运算 运算符new的功能是动态分配内存&#xff0c;或者称为动态创建堆对象&#xff0c;语法形式为&#xff1a; new 类型名T&#xff08;初值列表&…

参数变化_风机盘管参数变化对性能造成的影响

参数变化对性能造成的影响:1、风机盘管风量一定&#xff0c;供水温度一定&#xff0c;供水量变化时&#xff0c;制冷量随供水量的变化而变化&#xff0c;根据部分风机盘管产品性能统计&#xff0c;当供水温度为7℃&#xff0c;供水量减少到80%时&#xff0c;制冷量为原来的92%左…

Android基础总结(八)Service

服务两种启动方式&#xff08;掌握&#xff09; startService 开始服务&#xff0c;会使进程变成为服务进程启动服务的activity和服务不再有一毛钱关系bindService 绑定服务不会使进程变成服务进程绑定服务&#xff0c;是activity与服务建立连接&#xff0c;如果activity销毁了…

疲劳驾驶监测方案_【Nano Energy】TENG用于驾驶员驾驶状态监测

01研究背景研究表明&#xff0c;驾驶员的疲劳和分心会降低其感知能力和对汽车控制的决策能力。大约20%车祸和30%致命车祸的原因是由于驾驶员疲劳和注意力不集中造成的&#xff0c;同时也会导致单车撞击事故和大型车撞击事故发生率上升到50%。因此通过建立智能交通系统(ITS)来提…

升级Struts2.5后使用DMI动态方法调用遇到问题

转自&#xff1a;http://www.lvhongqiang.com/blog429.html 问题&#xff1a; 升级Struts2.5后使用DMI动态方法调用报错&#xff0c;method 找不到。 源码&#xff1a; struts.xml <action name"json_*_*" class"{1}Action" method"{2}"> …