Web テクノロジーの発展に伴い、JavaScript を使用してオブジェクトをカスタマイズすることがますます頻繁になってきており、作成したオブジェクトにもイベント メカニズムを持たせ、イベントを通じて外部と通信することで、開発効率を大幅に向上させることができます。次の記事では、JavaScript を使用して一連のカスタム イベント メカニズムを実装することに関する関連情報を主に紹介します。必要な方は参照してください。
前書き
イベント メカニズムは Web 開発に非常に便利で、実行する操作や実行するコードをいつでも指定できます。
たとえば、クリック イベントはユーザーがクリックするとトリガーされ、キーダウン イベントとキーアップ イベントはキーボードが押されるかポップアップされるとトリガーされ、アップロード コントロールでは、ファイルが追加される前とアップロードが完了した後にイベントがトリガーされます。
対応するイベントが適切なタイミングでトリガーされるため、これらのイベントに対応する処理関数を指定することができ、元のプロセスにさまざまなパーソナライズされた操作や処理を挿入することができ、プロセス全体をより効率的にすることができます。
クリック、ブラー、フォーカスなどのイベントは、元の DOM によって直接提供されるネイティブ イベントですが、通常、使用する他のコントロールで使用されるさまざまなイベントの一部は、ネイティブ DOM では利用できません。アップロード コントロールの開始イベントと終了イベントはどのように実装されるのでしょうか?
私が開発したコントロールに同様のイベントメカニズムを追加したいのですが、どうやって実装すればよいですか? 確認してみましょう。
イベントが持つべき機能
実装前に、まずイベント機構が持つべき基本的な機能を分析します。
簡単に言えば、イベントは次の機能を提供する必要があります:
イベントのバインド
イベントのトリガー
イベントのバインド解除
準備
やってみよう イベントの特徴を観察するイベントは特定のオブジェクトに属している必要があります。たとえば、focus イベントと Blur イベントはフォーカスを取得できる DOM 要素用、input イベントは入力ボックス用、アップロード開始とアップロード成功はアップロード成功用です。
言い換えれば、イベントは独立して存在するのではなく、キャリアを必要とします。では、イベントにキャリアを持たせるにはどうすればよいでしょうか?簡単な実装ソリューションは、イベントを基本クラスとして使用し、イベントが必要な場所でこのイベント クラスを継承することです。
バインディング イベント、トリガー イベント、バインド解除イベントにそれぞれ on、fire、off という名前を付けます。その後、次のイベント クラスを簡単に記述できます:
function CustomEvent() { this._events = {}; } CustomEvent.prototype = { constructor: CustomEvent, // 绑定事件 on: function () { }, // 触发事件 fire: function () { }, // 取消绑定事件 off: function () { } };
イベント バインディング
最初にイベント バインディングを実装し、イベント バインディングを実装する必要があります。イベントの種類とイベント処理関数を指定します。
それで、それ以外に何が必要ですか?カスタム イベントです。ネイティブ イベントのように、バブリング フェーズでトリガーされるかキャプチャ フェーズでトリガーされるかを指定する必要はありません。また、jQuery のように追加でトリガーする要素を指定する必要もありません。
イベント関数のこれは通常、現在のインスタンスです。イベント処理関数の実行中には、コンテキストを再指定する必要がある場合があります。
つまり、イベント バインディングを決定するときの 3 つのパラメーターは、イベント タイプ、イベント処理関数、イベント処理関数の実行コンテキストです。
それでは、イベント バインディングは何を行うのでしょうか? イベント バインディングは実際には、対応するイベント名とイベント処理関数を記録するだけです。
私の実装は次のとおりです:
{ /** * 绑定事件 * * @param {String} type 事件类型 * @param {Function} fn 事件处理函数 * @param {Object} scope 要为事件处理函数绑定的执行上下文 * @returns 当前实例对象 */ on: function (type, fn, scope) { if (type + '' !== type) { console && console.error && console.error('the first argument type is requird as string'); return this; } if (typeof fn != 'function') { console && console.error && console.error('the second argument fn is requird as function'); return this; } type = type.toLowerCase(); if (!this._events[type]) { this._events[type] = []; } this._events[type].push(scope ? [fn, scope] : [fn]); return this; } }
イベントは複数回バインドして順番に実行できるため、すべてのイベントタイプの処理関数は配列に格納されます。
イベントトリガー
イベントトリガーの基本的な機能は、ユーザーによってバインドされたイベントを実行することなので、イベントがトリガーされたときに指定された実行関数があるかどうかを確認するだけで済み、ある場合は、あれを呼べ。
さらに、イベントトリガーは実際にはユーザー指定の処理関数を実行するプロセスであり、多くのパーソナライズされた操作もユーザー指定のイベント処理関数内で実行されるため、この関数を実行するだけでは十分ではありません。また、クリックイベントの現在クリックされている要素、キーボードイベントの現在のキーのキーコード、アップロード開始とアップロード完了の現在のファイル情報など、現在の機能に必要な情報も提供する必要があります。
したがって、イベントがトリガーされると、イベント処理関数の実際のパラメーターには、現在のイベントの基本情報が含まれている必要があります。
さらに、イベント処理関数でのユーザーの操作により、後続の情報を調整する必要がある場合があります。たとえば、keydwon イベントでは、ユーザーはファイルをアップロードする前にこのキーの入力を禁止できます。イベント内のファイルのアップロードをキャンセルするか、一部のファイル情報を変更します。したがって、イベントトリガー関数は、ユーザーによって変更されたイベントオブジェクトを返す必要があります。
私の実装は次のとおりです:
{ /** * 触发事件 * * @param {String} type 触发事件的名称 * @param {Object} data 要额外传递的数据,事件处理函数参数如下 * event = { // 事件类型 type: type, // 绑定的源,始终为当前实例对象 origin: this, // 事件处理函数中的执行上下文 为 this 或用户指定的上下文对象 scope :this/scope // 其他数据 为fire时传递的数据 } * @returns 事件对象 */ fire: function (type, data) { type = type.toLowerCase(); var eventArr = this._events[type]; var fn, // event = { // // 事件类型 // type: type, // // 绑定的源 // origin: this, // // scope 为 this 或用户指定的上下文, // // 其他数据 // data: data, // // 是否取消 // cancel: false // }; // 上面对自定义参数的处理不便于使用 将相关属性直接合并到事件参数中 event = $.extend({ // 事件类型 type: type, // 绑定的源 origin: this, // scope 为 this 或用户指定的上下文, // 其他数据 // data: data, // 是否取消 cancel: false }, data); if (!eventArr) { return event; } for (var i = 0, l = eventArr.length; i < l; ++i) { fn = eventArr[i][0]; event.scope = eventArr[i][1] || this; fn.call(event.scope, event); } return event; } }
上記の実装でイベント処理関数に指定される実際のパラメータには、次の情報が含まれている必要があります:
type : 現在トリガーされているイベントのタイプ
origin :現在のイベントは、オブジェクト
スコープ: イベント処理関数
の実行コンテキストにバインドされています。 さらに、さまざまなイベントがトリガーされたときに、このイベント オブジェクトにさまざまな情報を追加できます。
关于 Object.assign(target, ...sources)
是ES6中的一个方法,作用是将所有可枚举属性的值从一个或多个源对象复制到目标对象,并返回目标对象,类似于大家熟知的$.extend(target,..sources)
方法。
事件取消
事件取消中需要做的就是已经绑定的事件处理函数移除掉即可。
实现如下:
{ /** * 取消绑定一个事件 * * @param {String} type 取消绑定的事件名称 * @param {Function} fn 要取消绑定的事件处理函数,不指定则移除当前事件类型下的全部处理函数 * @returns 当前实例对象 */ off: function (type, fn) { type = type.toLowerCase(); var eventArr = this._events[type]; if (!eventArr || !eventArr.length) return this; if (!fn) { this._events[type] = eventArr = []; } else { for (var i = 0; i < eventArr.length; ++i) { if (fn === eventArr[i][0]) { eventArr.splice(i, 1); // 1、找到后不能立即 break 可能存在一个事件一个函数绑定多次的情况 // 删除后数组改变,下一个仍然需要遍历处理! --i; } } } return this; } }
此处实现类似原生的事件取消绑定,如果指定了事件处理函数则移除指定事件的指定处理函数,如果省略事件处理函数则移除当前事件类型下的所有事件处理函数。
仅触发一次的事件
jQuery中有一个 one 方法,它所绑定的事件仅会执行一次,此方法在一些特定情况下非常有用,不需要用户手动取消绑定这个事件。
这里的实现也非常简单,只用在触发这个事件时取消绑定即可。
实现如下:
{ /** * 绑定一个只执行一次的事件 * * @param {String} type 事件类型 * @param {Function} fn 事件处理函数 * @param {Object} scope 要为事件处理函数绑定的执行上下文 * @returns 当前实例对象 */ one: function (type, fn, scope) { var that = this; function nfn() { // 执行时 先取消绑定 that.off(type, nfn); // 再执行函数 fn.apply(scope || that, arguments); } this.on(type, nfn, scope); return this; } }
原理则是不把用户指定的函数直接绑定上去,而是生成一个新的函数,并绑定,此函数执行时会先取消绑定,再执行用户指定的处理函数。
基本雏形
到此,一套完整的事件机制就已经完成了,完整代码如下:
function CustomEvent() { this._events = {}; } CustomEvent.prototype = { constructor: CustomEvent, /** * 绑定事件 * * @param {String} type 事件类型 * @param {Function} fn 事件处理函数 * @param {Object} scope 要为事件处理函数绑定的执行上下文 * @returns 当前实例对象 */ on: function (type, fn, scope) { if (type + '' !== type) { console && console.error && console.error('the first argument type is requird as string'); return this; } if (typeof fn != 'function') { console && console.error && console.error('the second argument fn is requird as function'); return this; } type = type.toLowerCase(); if (!this._events[type]) { this._events[type] = []; } this._events[type].push(scope ? [fn, scope] : [fn]); return this; }, /** * 触发事件 * * @param {String} type 触发事件的名称 * @param {Anything} data 要额外传递的数据,事件处理函数参数如下 * event = { // 事件类型 type: type, // 绑定的源,始终为当前实例对象 origin: this, // 事件处理函数中的执行上下文 为 this 或用户指定的上下文对象 scope :this/scope // 其他数据 为fire时传递的数据 } * @returns 事件对象 */ fire: function (type, data) { type = type.toLowerCase(); var eventArr = this._events[type]; var fn, scope, event = Object.assign({ // 事件类型 type: type, // 绑定的源 origin: this, // scope 为 this 或用户指定的上下文, // 是否取消 cancel: false }, data); if (!eventArr) return event; for (var i = 0, l = eventArr.length; i < l; ++i) { fn = eventArr[i][0]; scope = eventArr[i][1]; if (scope) { event.scope = scope; fn.call(scope, event); } else { event.scope = this; fn(event); } } return event; }, /** * 取消绑定一个事件 * * @param {String} type 取消绑定的事件名称 * @param {Function} fn 要取消绑定的事件处理函数,不指定则移除当前事件类型下的全部处理函数 * @returns 当前实例对象 */ off: function (type, fn) { type = type.toLowerCase(); var eventArr = this._events[type]; if (!eventArr || !eventArr.length) return this; if (!fn) { this._events[type] = eventArr = []; } else { for (var i = 0; i < eventArr.length; ++i) { if (fn === eventArr[i][0]) { eventArr.splice(i, 1); // 1、找到后不能立即 break 可能存在一个事件一个函数绑定多次的情况 // 删除后数组改变,下一个仍然需要遍历处理! --i; } } } return this; }, /** * 绑定一个只执行一次的事件 * * @param {String} type 事件类型 * @param {Function} fn 事件处理函数 * @param {Object} scope 要为事件处理函数绑定的执行上下文 * @returns 当前实例对象 */ one: function (type, fn, scope) { var that = this; function nfn() { // 执行时 先取消绑定 that.off(type, nfn); // 再执行函数 fn.apply(scope || that, arguments); } this.on(type, nfn, scope); return this; } };
在自己的控件中使用
上面已经实现了一套事件机制,我们如何在自己的事件中使用呢。
比如我写了一个日历控件,需要使用事件机制。
function Calendar() { // 加入事件机制的存储的对象 this._event = {}; // 日历的其他实现 } Calendar.prototype = { constructor:Calendar, on:function () {}, off:function () {}, fire:function () {}, one:function () {}, // 日历的其他实现 。。。 }
以上伪代码作为示意,仅需在让控件继承到on、off 、fire 、one等方法即可。但是必须保证事件的存储对象_events 必须是直接加载实例上的,这点需要在继承时注意,JavaScript中实现继承的方案太多了。
上面为日历控件Calendar中加入了事件机制,之后就可以在Calendar中使用了。
如在日历开发时,我们在日历的单元格渲染时触发cellRender事件。
// 每天渲染时发生 还未插入页面 var renderEvent = this.fire('cellRender', { // 当天的完整日期 date: date.format('YYYY-MM-DD'), // 当天的iso星期 isoWeekday: day, // 日历dom el: this.el, // 当前单元格 tdEl: td, // 日期文本 dateText: text.innerText, // 日期class dateCls: text.className, // 需要注入的额外的html extraHtml: '', isHeader: false });
在事件中,我们将当前渲染的日期、文本class等信息都提供给用户,这样用户就可以绑定这个事件,在这个事件中进行自己的个性阿化处理了。
如在渲染时,如果是周末则插入一个"假"的标识,并让日期显示为红色。
var calendar = new Calendar(); calendar.on('cellRender', function (e) { if(e.isoWeekday > 5 ) { e.extraHtml = '<span>假</span>'; e.dateCls += ' red'; } });
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
以上がJavascript を使用してカスタム イベント メカニズムを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

はい、JavaScriptのエンジンコアはCで記述されています。1)C言語は、JavaScriptエンジンの開発に適した効率的なパフォーマンスと基礎となる制御を提供します。 2)V8エンジンを例にとると、そのコアはCで記述され、Cの効率とオブジェクト指向の特性を組み合わせて書かれています。3)JavaScriptエンジンの作業原理には、解析、コンパイル、実行が含まれ、C言語はこれらのプロセスで重要な役割を果たします。

JavaScriptは、Webページのインタラクティブ性とダイナミズムを向上させるため、現代のWebサイトの中心にあります。 1)ページを更新せずにコンテンツを変更できます。2)Domapiを介してWebページを操作する、3)アニメーションやドラッグアンドドロップなどの複雑なインタラクティブ効果、4)ユーザーエクスペリエンスを改善するためのパフォーマンスとベストプラクティスを最適化します。

CおよびJavaScriptは、WebAssemblyを介して相互運用性を実現します。 1)CコードはWebAssemblyモジュールにコンパイルされ、JavaScript環境に導入され、コンピューティングパワーが強化されます。 2)ゲーム開発では、Cは物理エンジンとグラフィックスレンダリングを処理し、JavaScriptはゲームロジックとユーザーインターフェイスを担当します。

JavaScriptは、Webサイト、モバイルアプリケーション、デスクトップアプリケーション、サーバー側のプログラミングで広く使用されています。 1)Webサイト開発では、JavaScriptはHTMLおよびCSSと一緒にDOMを運用して、JQueryやReactなどのフレームワークをサポートします。 2)ReactNativeおよびIonicを通じて、JavaScriptはクロスプラットフォームモバイルアプリケーションを開発するために使用されます。 3)電子フレームワークにより、JavaScriptはデスクトップアプリケーションを構築できます。 4)node.jsを使用すると、JavaScriptがサーバー側で実行され、高い並行リクエストをサポートします。

Pythonはデータサイエンスと自動化により適していますが、JavaScriptはフロントエンドとフルスタックの開発により適しています。 1. Pythonは、データ処理とモデリングのためにNumpyやPandasなどのライブラリを使用して、データサイエンスと機械学習でうまく機能します。 2。Pythonは、自動化とスクリプトにおいて簡潔で効率的です。 3. JavaScriptはフロントエンド開発に不可欠であり、動的なWebページと単一ページアプリケーションの構築に使用されます。 4. JavaScriptは、node.jsを通じてバックエンド開発において役割を果たし、フルスタック開発をサポートします。

CとCは、主に通訳者とJITコンパイラを実装するために使用されるJavaScriptエンジンで重要な役割を果たします。 1)cは、JavaScriptソースコードを解析し、抽象的な構文ツリーを生成するために使用されます。 2)Cは、Bytecodeの生成と実行を担当します。 3)Cは、JITコンパイラを実装し、実行時にホットスポットコードを最適化およびコンパイルし、JavaScriptの実行効率を大幅に改善します。

現実世界でのJavaScriptのアプリケーションには、フロントエンドとバックエンドの開発が含まれます。 1)DOM操作とイベント処理を含むTODOリストアプリケーションを構築して、フロントエンドアプリケーションを表示します。 2)node.jsを介してRestfulapiを構築し、バックエンドアプリケーションをデモンストレーションします。

Web開発におけるJavaScriptの主な用途には、クライアントの相互作用、フォーム検証、非同期通信が含まれます。 1)DOM操作による動的なコンテンツの更新とユーザーインタラクション。 2)ユーザーエクスペリエンスを改善するためにデータを提出する前に、クライアントの検証が実行されます。 3)サーバーとのリフレッシュレス通信は、AJAXテクノロジーを通じて達成されます。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

PhpStorm Mac バージョン
最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 Linux 新バージョン
SublimeText3 Linux 最新バージョン

mPDF
mPDF は、UTF-8 でエンコードされた HTML から PDF ファイルを生成できる PHP ライブラリです。オリジナルの作者である Ian Back は、Web サイトから「オンザフライ」で PDF ファイルを出力し、さまざまな言語を処理するために mPDF を作成しました。 HTML2FPDF などのオリジナルのスクリプトよりも遅く、Unicode フォントを使用すると生成されるファイルが大きくなりますが、CSS スタイルなどをサポートし、多くの機能強化が施されています。 RTL (アラビア語とヘブライ語) や CJK (中国語、日本語、韓国語) を含むほぼすべての言語をサポートします。ネストされたブロックレベル要素 (P、DIV など) をサポートします。

SAP NetWeaver Server Adapter for Eclipse
Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

ホットトピック









