如何从另一个页面创建实时文本显示切换器?
How to create a real time text display toggler from another page?
大家好我正在尝试创建一个显示切换器,我有 2 页 index.html 和 toggler.html,index.html 显示“TEXT”并且 toggler.html 包含切换器或开关按钮。如果 TOGGLER 开启,TEXT 将显示在 index.html 中,否则它将消失。
要求:
- 文本会实时显示和消失。
- 只要切换器打开,文本就会保留在页面中,即使您刷新 index.html 页面也是如此。
- TOGGLER 的默认值 (OFF) 将在午夜(新日期)后重置。
关于如何用最少的代码可靠地实现这一点的任何建议。
网络套接字
在这个例子中Ratched
通过 Composer 安装:composer require cboden/ratchet
socket.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
class Socket implements MessageComponentInterface {
protected $clients;
private $state = 0;
private $date;
public function __construct() {
$this->clients = new \SplObjectStorage;
$this->date = date("G");//Saves the date the day the socket was started
}
public function dateListener(){
$d = date("G");
if($d < $this->date){//check if day has changed
$this->state = 0;
$this->date = $d;
foreach($this->clients as $client){//resetting the state to default(0)
$client->send($this->state);
}
}
}
public function onOpen(ConnectionInterface $conn) {
// Store the new connection to send messages to later
$this->clients->attach($conn);
foreach($this->clients as $client){
//if a new client connects it gets the current state
$client->send($this->state);
}
echo "New connection! ({$conn->resourceId})\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
$numRecv = count($this->clients) - 1;
echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n"
, $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');
foreach ($this->clients as $client) {
if ($from !== $client) {
// The sender is not the receiver, send to each client connected
if($msg == 1){//changing state and sending it to all clients
$this->state = 1;
$client->send($this->state);
}else if($msg == 0){
$this->state = 0;
$client->send($this->state);
}
}
}
}
public function onClose(ConnectionInterface $conn) {
// The connection is closed, remove it, as we can no longer send it messages
$this->clients->detach($conn);
echo "Connection {$conn->resourceId} has disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
}
// Run the server application through the WebSocket protocol on port 8080
$sckt = new Socket();
$server = IoServer::factory(
new HttpServer(
new WsServer(
$sckt
)
),
8080
);
//to check continuously if the date has changed
$server->loop->addPeriodicTimer(5, function () use ($sckt) {
echo $sckt->dateListener();
});
$server->run();
index.html
<!DOCTYPE html>
<html>
<head>
<title>Index</title>
</head>
<body>
<div id="text"></div>
</body>
<script>
var conn = new WebSocket('ws://localhost:8080');//connect
conn.onopen = function(e) {
console.log("Connection established!");
};
conn.onmessage = function(e) {//receive current state
var div = document.getElementById("text");
if (e.data == 1){
div.innerHTML = "text";//your text
}else if (e.data == 0){
div.innerHTML = "";
}
};
</script>
</html>
switch.html
<!DOCTYPE html>
<html>
<head>
<title>switch</title>
</head>
<body>
<button onclick="sendToggle()">Toggle</button>
</body>
<script>
var conn = new WebSocket('ws://localhost:8080');//connect
var toggle = 1;
conn.onopen = function (e) {
console.log("Connection established!");
};
conn.onmessage = function (e) {//receive current state
if(e.data == 1){
toggle = 1;
}else if(e.data == 0){
toggle = 0
}
};
this.send = function (message, callback) {
this.waitForConnection(function () {
conn.send(message);
if (typeof callback !== 'undefined') {
callback();
}
}, 1000);
};
this.waitForConnection = function (callback, interval) {
if (conn.readyState === 1) {
callback();
} else {
var that = this;
// optional: implement backoff for interval here
setTimeout(function () {
that.waitForConnection(callback, interval);
}, interval);
}
};
function sendToggle() {//send new state by pressing the button
if (toggle == 1) {
this.send("0",function(){
console.log("sent");
toggle = 0;
});
} else {
this.send("1",function(){
console.log("sent");
toggle = 1;
});
}
}
</script>
</html>
要启动 websocket 只需 运行 下面的命令
php socket.php
要部署此版本,您需要通过 ssh 访问您的服务器 运行 socket.php
。因此,当您关闭终端时文件的执行不会停止 window 您需要创建一个 screen 会话。
要在 linux 服务器上安装屏幕,请执行以下操作:
在 Ubuntu 或 Debian
上
sudo apt-get install screen
在 CentOS 和 Fedora 上
sudo yum install screen
要启动屏幕会话类型 screen
。开始会话后导航到您的 websocket.php
和 运行 它。要从会话中分离,只需键入 Ctrl+a d
编辑
使用long pulling也是一种选择。
这消除了 ssh 访问的需要。
我正在使用 ajax 通过向服务器发出请求来获取和更改当前状态
创建以下文件结构:
-client.js
-index.html
-switch.html
-switch.js
--/server
-changeState.php
-data.txt
-server.php
延长 this
index.html
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script type="text/javascript" src="client.js"></script>
</head>
<body>
<h1>Response from server:</h1>
<div id="response"></div>
</body>
</html>
switch.html
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script type="text/javascript" src="switch.js"></script>
</head>
<body>
<button id="toggler" state="" onclick="toggleState()">Toggle</button>
<script>
toggleState();//to get current state
</script>
</body>
</html>
在两个 ajax 请求中更改 url 参数以部署它。
client.js
/**
* AJAX long-polling
*
* 1. sends a request to the server (without a timestamp parameter)
* 2. waits for an answer from server.php (which can take forever)
* 3. if server.php responds (whenever), put data_from_file into #response
* 4. and call the function again
*
* @param timestamp
*/
function getContent(timestamp)
{
var queryString = {'timestamp' : timestamp};
$.ajax(
{
type: 'GET',
url: 'http://localhost:80/longPulling/server/server.php',
data: queryString,
success: function(data){
// put result data into "obj"
console.log(data);
var obj = jQuery.parseJSON(data);
// put the data_from_file into #response
$('#response').html(obj.data_from_file);
// call the function again, this time with the timestamp we just got from server.php
getContent(obj.timestamp);
}
}
);
}
// initialize jQuery
$(function() {
getContent();
});
switch.js
function toggleState()
{
var currentState = $("#toggler").attr("state")
console.log("currentState: "+currentState);
var queryString = {};
if(currentState == ""){
queryString = {'state' : 0};//default state
}else{
queryString = {'state' : currentState}
}
$.ajax(
{
type: 'GET',
url: 'http://localhost:80/longPulling/server/changeState.php',
data: queryString,
success: function(data){
// put result data into "obj"
var obj = jQuery.parseJSON(data);
$("#toggler").attr("state",obj.state);
}
}
);
}
// initialize jQuery
$(function() {
toggleState();
});
提供当前状态
server/server.php
<?php
/**
* Server-side file.
* This file is an infinitive loop. Seriously.
* It gets the file data.txt's last-changed timestamp, checks if this is larger than the timestamp of the
* AJAX-submitted timestamp (time of last ajax request), and if so, it sends back a JSON with the data from
* data.txt (and a timestamp). If not, it waits for one seconds and then start the next while step.
*
* Note: This returns a JSON, containing the content of data.txt and the timestamp of the last data.txt change.
* This timestamp is used by the client's JavaScript for the next request, so THIS server-side script here only
* serves new content after the last file change. Sounds weird, but try it out, you'll get into it really fast!
*/
// set php runtime to unlimited
set_time_limit(0);
// where does the data come from ? In real world this would be a SQL query or something
$data_source_file = 'data.txt';
// If your using a database your table needs to following columns
// ID state createdAt
//
// $sql = "SELECT * FROM mytable ORDER BY ID DESC LIMIT 1"
// $servername = "localhost";
// $username = "username";
// $password = "password";
// $dbName = "myDataBase"
// // Create connection
// $conn = new mysqli($servername, $username, $password, $dbName);
// // Check connection
// if ($conn->connect_error) {
// die("Connection failed: " . $conn->connect_error);
// }
//
// $result = $conn->query($sql);
// $row = $result->fetch_assoc();
// $lastChanged = $row['created_at'];
// $currentState = $row['state'];
// main loop
while (true) {
// if ajax request has send a timestamp, then $last_ajax_call = timestamp, else $last_ajax_call = null
$last_ajax_call = isset($_GET['timestamp']) ? (int)$_GET['timestamp'] : null;
// PHP caches file data, like requesting the size of a file, by default. clearstatcache() clears that cache
clearstatcache();
// get timestamp of when file has been changed the last time
// use $lastChanged if using database
$last_change_in_data_file = filemtime($data_source_file);
// if no timestamp delivered via ajax or data.txt has been changed SINCE last ajax timestamp
if ($last_ajax_call == null || $last_change_in_data_file > $last_ajax_call) {
// get content of data.txt
// use $state if using database
$data = file_get_contents($data_source_file);
// put data.txt's content and timestamp of last data.txt change into array
$result = array(
'data_from_file' => $data,
'timestamp' => $last_change_in_data_file
);
// encode to JSON, render the result (for AJAX)
$json = json_encode($result);
echo $json;
// leave this loop step
break;
} else {
// wait for 1 sec (not very sexy as this blocks the PHP/Apache process, but that's how it goes)
sleep( 1 );
continue;
}
}
改变当前状态
server/changeState.php
<?php
//copy database connection from server.php
if(isset($_GET['state']) && ($_GET['state'] == 1 || $_GET['state'] == 0)){
$newState = 0;
if($_GET['state'] == 0){
$newState = 1;
}
// $sql = "INSERT INTO mytable (state) VALUES ($newState);"
// if ($conn->query($sql) === TRUE) {
// echo "New record created successfully";
// } else {
// echo "Error: " . $sql . "<br>" . $conn->error;
// }
file_put_contents("data.txt", $newState);
$response = array(
'state' => $newState
);
$json = json_encode($response);
echo $json;
}else{
//look into server.php how to get data out of database
$content = trim(file_get_contents("data.txt"));
if($content == 1 || $content == 0){
$response = array(
'state' => $content
);
$json = json_encode($response);
echo $json;
}else{
//copy content insertion from above
file_put_contents("data.txt", 0);
$response = array(
'state' => 0
);
$json = json_encode($response);
echo $json;
}
}
存储当前状态
server/data.txt
0
您应该在本地创建文件结构,然后将文件夹上传到您的服务器。
它不是很性感,但很管用。
大家好我正在尝试创建一个显示切换器,我有 2 页 index.html 和 toggler.html,index.html 显示“TEXT”并且 toggler.html 包含切换器或开关按钮。如果 TOGGLER 开启,TEXT 将显示在 index.html 中,否则它将消失。
要求:
- 文本会实时显示和消失。
- 只要切换器打开,文本就会保留在页面中,即使您刷新 index.html 页面也是如此。
- TOGGLER 的默认值 (OFF) 将在午夜(新日期)后重置。
关于如何用最少的代码可靠地实现这一点的任何建议。
网络套接字
在这个例子中Ratched
通过 Composer 安装:composer require cboden/ratchet
socket.php
<?php
require __DIR__ . '/vendor/autoload.php';
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
class Socket implements MessageComponentInterface {
protected $clients;
private $state = 0;
private $date;
public function __construct() {
$this->clients = new \SplObjectStorage;
$this->date = date("G");//Saves the date the day the socket was started
}
public function dateListener(){
$d = date("G");
if($d < $this->date){//check if day has changed
$this->state = 0;
$this->date = $d;
foreach($this->clients as $client){//resetting the state to default(0)
$client->send($this->state);
}
}
}
public function onOpen(ConnectionInterface $conn) {
// Store the new connection to send messages to later
$this->clients->attach($conn);
foreach($this->clients as $client){
//if a new client connects it gets the current state
$client->send($this->state);
}
echo "New connection! ({$conn->resourceId})\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
$numRecv = count($this->clients) - 1;
echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n"
, $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');
foreach ($this->clients as $client) {
if ($from !== $client) {
// The sender is not the receiver, send to each client connected
if($msg == 1){//changing state and sending it to all clients
$this->state = 1;
$client->send($this->state);
}else if($msg == 0){
$this->state = 0;
$client->send($this->state);
}
}
}
}
public function onClose(ConnectionInterface $conn) {
// The connection is closed, remove it, as we can no longer send it messages
$this->clients->detach($conn);
echo "Connection {$conn->resourceId} has disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
}
// Run the server application through the WebSocket protocol on port 8080
$sckt = new Socket();
$server = IoServer::factory(
new HttpServer(
new WsServer(
$sckt
)
),
8080
);
//to check continuously if the date has changed
$server->loop->addPeriodicTimer(5, function () use ($sckt) {
echo $sckt->dateListener();
});
$server->run();
index.html
<!DOCTYPE html>
<html>
<head>
<title>Index</title>
</head>
<body>
<div id="text"></div>
</body>
<script>
var conn = new WebSocket('ws://localhost:8080');//connect
conn.onopen = function(e) {
console.log("Connection established!");
};
conn.onmessage = function(e) {//receive current state
var div = document.getElementById("text");
if (e.data == 1){
div.innerHTML = "text";//your text
}else if (e.data == 0){
div.innerHTML = "";
}
};
</script>
</html>
switch.html
<!DOCTYPE html>
<html>
<head>
<title>switch</title>
</head>
<body>
<button onclick="sendToggle()">Toggle</button>
</body>
<script>
var conn = new WebSocket('ws://localhost:8080');//connect
var toggle = 1;
conn.onopen = function (e) {
console.log("Connection established!");
};
conn.onmessage = function (e) {//receive current state
if(e.data == 1){
toggle = 1;
}else if(e.data == 0){
toggle = 0
}
};
this.send = function (message, callback) {
this.waitForConnection(function () {
conn.send(message);
if (typeof callback !== 'undefined') {
callback();
}
}, 1000);
};
this.waitForConnection = function (callback, interval) {
if (conn.readyState === 1) {
callback();
} else {
var that = this;
// optional: implement backoff for interval here
setTimeout(function () {
that.waitForConnection(callback, interval);
}, interval);
}
};
function sendToggle() {//send new state by pressing the button
if (toggle == 1) {
this.send("0",function(){
console.log("sent");
toggle = 0;
});
} else {
this.send("1",function(){
console.log("sent");
toggle = 1;
});
}
}
</script>
</html>
要启动 websocket 只需 运行 下面的命令
php socket.php
要部署此版本,您需要通过 ssh 访问您的服务器 运行 socket.php
。因此,当您关闭终端时文件的执行不会停止 window 您需要创建一个 screen 会话。
要在 linux 服务器上安装屏幕,请执行以下操作:
在 Ubuntu 或 Debian
上sudo apt-get install screen
在 CentOS 和 Fedora 上
sudo yum install screen
要启动屏幕会话类型 screen
。开始会话后导航到您的 websocket.php
和 运行 它。要从会话中分离,只需键入 Ctrl+a d
编辑
使用long pulling也是一种选择。 这消除了 ssh 访问的需要。
我正在使用 ajax 通过向服务器发出请求来获取和更改当前状态
创建以下文件结构:
-client.js
-index.html
-switch.html
-switch.js
--/server
-changeState.php
-data.txt
-server.php
延长 this
index.html
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script type="text/javascript" src="client.js"></script>
</head>
<body>
<h1>Response from server:</h1>
<div id="response"></div>
</body>
</html>
switch.html
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script type="text/javascript" src="switch.js"></script>
</head>
<body>
<button id="toggler" state="" onclick="toggleState()">Toggle</button>
<script>
toggleState();//to get current state
</script>
</body>
</html>
在两个 ajax 请求中更改 url 参数以部署它。
client.js
/**
* AJAX long-polling
*
* 1. sends a request to the server (without a timestamp parameter)
* 2. waits for an answer from server.php (which can take forever)
* 3. if server.php responds (whenever), put data_from_file into #response
* 4. and call the function again
*
* @param timestamp
*/
function getContent(timestamp)
{
var queryString = {'timestamp' : timestamp};
$.ajax(
{
type: 'GET',
url: 'http://localhost:80/longPulling/server/server.php',
data: queryString,
success: function(data){
// put result data into "obj"
console.log(data);
var obj = jQuery.parseJSON(data);
// put the data_from_file into #response
$('#response').html(obj.data_from_file);
// call the function again, this time with the timestamp we just got from server.php
getContent(obj.timestamp);
}
}
);
}
// initialize jQuery
$(function() {
getContent();
});
switch.js
function toggleState()
{
var currentState = $("#toggler").attr("state")
console.log("currentState: "+currentState);
var queryString = {};
if(currentState == ""){
queryString = {'state' : 0};//default state
}else{
queryString = {'state' : currentState}
}
$.ajax(
{
type: 'GET',
url: 'http://localhost:80/longPulling/server/changeState.php',
data: queryString,
success: function(data){
// put result data into "obj"
var obj = jQuery.parseJSON(data);
$("#toggler").attr("state",obj.state);
}
}
);
}
// initialize jQuery
$(function() {
toggleState();
});
提供当前状态
server/server.php
<?php
/**
* Server-side file.
* This file is an infinitive loop. Seriously.
* It gets the file data.txt's last-changed timestamp, checks if this is larger than the timestamp of the
* AJAX-submitted timestamp (time of last ajax request), and if so, it sends back a JSON with the data from
* data.txt (and a timestamp). If not, it waits for one seconds and then start the next while step.
*
* Note: This returns a JSON, containing the content of data.txt and the timestamp of the last data.txt change.
* This timestamp is used by the client's JavaScript for the next request, so THIS server-side script here only
* serves new content after the last file change. Sounds weird, but try it out, you'll get into it really fast!
*/
// set php runtime to unlimited
set_time_limit(0);
// where does the data come from ? In real world this would be a SQL query or something
$data_source_file = 'data.txt';
// If your using a database your table needs to following columns
// ID state createdAt
//
// $sql = "SELECT * FROM mytable ORDER BY ID DESC LIMIT 1"
// $servername = "localhost";
// $username = "username";
// $password = "password";
// $dbName = "myDataBase"
// // Create connection
// $conn = new mysqli($servername, $username, $password, $dbName);
// // Check connection
// if ($conn->connect_error) {
// die("Connection failed: " . $conn->connect_error);
// }
//
// $result = $conn->query($sql);
// $row = $result->fetch_assoc();
// $lastChanged = $row['created_at'];
// $currentState = $row['state'];
// main loop
while (true) {
// if ajax request has send a timestamp, then $last_ajax_call = timestamp, else $last_ajax_call = null
$last_ajax_call = isset($_GET['timestamp']) ? (int)$_GET['timestamp'] : null;
// PHP caches file data, like requesting the size of a file, by default. clearstatcache() clears that cache
clearstatcache();
// get timestamp of when file has been changed the last time
// use $lastChanged if using database
$last_change_in_data_file = filemtime($data_source_file);
// if no timestamp delivered via ajax or data.txt has been changed SINCE last ajax timestamp
if ($last_ajax_call == null || $last_change_in_data_file > $last_ajax_call) {
// get content of data.txt
// use $state if using database
$data = file_get_contents($data_source_file);
// put data.txt's content and timestamp of last data.txt change into array
$result = array(
'data_from_file' => $data,
'timestamp' => $last_change_in_data_file
);
// encode to JSON, render the result (for AJAX)
$json = json_encode($result);
echo $json;
// leave this loop step
break;
} else {
// wait for 1 sec (not very sexy as this blocks the PHP/Apache process, but that's how it goes)
sleep( 1 );
continue;
}
}
改变当前状态
server/changeState.php
<?php
//copy database connection from server.php
if(isset($_GET['state']) && ($_GET['state'] == 1 || $_GET['state'] == 0)){
$newState = 0;
if($_GET['state'] == 0){
$newState = 1;
}
// $sql = "INSERT INTO mytable (state) VALUES ($newState);"
// if ($conn->query($sql) === TRUE) {
// echo "New record created successfully";
// } else {
// echo "Error: " . $sql . "<br>" . $conn->error;
// }
file_put_contents("data.txt", $newState);
$response = array(
'state' => $newState
);
$json = json_encode($response);
echo $json;
}else{
//look into server.php how to get data out of database
$content = trim(file_get_contents("data.txt"));
if($content == 1 || $content == 0){
$response = array(
'state' => $content
);
$json = json_encode($response);
echo $json;
}else{
//copy content insertion from above
file_put_contents("data.txt", 0);
$response = array(
'state' => 0
);
$json = json_encode($response);
echo $json;
}
}
存储当前状态 server/data.txt
0
您应该在本地创建文件结构,然后将文件夹上传到您的服务器。
它不是很性感,但很管用。