PHPで出力するDOMをJSで自動オブジェクト化


PHP, JS, HTML の連携

PHPとJSを行き来するのめんどくさい…となっていた時に試してみた方法をメモ。

index.php
<script type="text/javascript">
/**
 * DOMと紐付けるオブジェクト。
 * @param[in] name 紐付けに使う名前。ID、クラス名で使用される。
 */
Object = function(name) {
        this._name = name;
        this._root = document.getElementById(name);

        this._root.getElementsByTagName('p')[0].textContent = name;
};

Object.prototype.getName = function() {
        return this._name;
};
</script>

<?php
/**
 * DOMを出力し、JSとの紐付けを行う。
 * @param[in] $name 紐付けに使う名前。
 */
function render_object($name) {
?>
<div id="<?php echo $name; ?>" class="<?php echo $name; ?>">
        <p>content</p>
</div>
<script type="text/javascript">
/// JSをインライン展開して紐付けを行う。
(function() {
        var obj = new Object('<?php echo $name; ?>');
        console.log(obj.getName());
}());
</script>
<?php
}

/// 開発者が再利用するコード。
$number = 0;
render_object("object_" . $number++);
render_object("object_" . $number++);

?>

結果のHTML.

result
<script type="text/javascript">
Object = function(name) {
    this._name = name;
    this._root = document.getElementById(name);

    this._root.getElementsByTagName('p')[0].textContent = name;
};

Object.prototype.getName = function() {
    return this._name;
};
</script>

<div id="object_0" class="object_0">
    <p>content</p>
</div>
<script type="text/javascript">
(function() {
    var obj = new Object('object_0');
    console.log(obj.getName());
}());
</script>
<div id="object_1" class="object_1">
    <p>content</p>
</div>
<script type="text/javascript">
(function() {
    var obj = new Object('object_1');
    console.log(obj.getName());
}());
</script>

結果のJSコンソール.

result
"object_0" index.php:20:1
"object_1" index.php:29:1

クラス化してカウンターを作る

UI.php に関してはクラス化する必要があるのかまだ謎。
関数で足りる気もする。サーバー/クライアントサイドでオブジェクト分 new してる。
あと名前の共有も両サイドで必要。PHPに関しては名前の管理者も必要。
それから JS で getElementById() 使ってるから走査する分時間もかかってそう。

index.php
<script type="text/javascript" src="ui.js"></script>

<?php
require_once(dirname(__FILE__) . '/UI.php');


/// TODO: You should be created Class for name
$prefix_name = 'counter_widget';
$suffix_number = 0;


$counter_0 = new UI\Counter($prefix_name . '_' . $suffix_number++);
$counter_1 = new UI\Counter($prefix_name . '_' . $suffix_number++);

$counter_0->render();
$counter_1->render();


?>

UI.php
<?php
namespace UI;


/**
 * UI\Counter
 * @see ui.js
 */
class Counter {
        private $_name;

        function __construct($name) {
                $this->_name = $name;
        }

        /**
         * render html and associate by inline JS
         */
        public function render() {
        ?>
                <div id="<?php echo $this->_name; ?>" class="<?php echo $this->_name; ?>">
                        <div class="display">display</div>
                        <input class="button" type="button" value="click me" />
                </div>

                <script type="text/javascript">
                (function() {
                        var counter = new UI.Counter('<?php echo $this->_name; ?>');
                        counter.build();
                }());
                </script>
        <?php
        }
}


?>

ui.js
/// namespace
UI = {};

/**
 * UI.Counter
 *
 * @param[in] name widget name string
 */
UI.Counter = function(name) {
        this._name = name;
        this._root = document.getElementById(name);
        if (this._root == null) {
                console.error('not found name "' + name + '"');
                return;
        }
        this._counter = 0;
};

/**
 * build logic with root node
 */
UI.Counter.prototype.build = function() {
        var self = this;  /// alias for this

        var display = self._root.getElementsByClassName('display')[0];
        var button = self._root.getElementsByClassName('button')[0];

        button.addEventListener('click', function() {
                display.textContent = self._counter++;
        });
};

result