質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.36%

NodeでjQuery使用

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,982

Fujiman

score 19

deprecateという感じですがNode環境ででjQueryを使えるようにしておく必要があり
以下のようにしましたが、jQueryのメソッドチェーンがfind()以降、
つなげることができません。jQueryのオブジェクトが返ってきていないようです

/*
  input.html の内容の一部を変更して output.html に書き込むというものです
*/

var $ = require('jquery');
var fs = require('fs');
var jsdom = require('jsdom');
const { JSDOM } = jsdom;

fs.readFile(__dirname + '/input.html', function (err, data) {
    if (err) throw err;
    let body = data.toString();
    const dom = new JSDOM(body);

    // Error(jQuery)
    let newBody = $(dom.window.window).find('h1')[0].text('Hello World').parents('html')[0].outerHTML;

    fs.writeFile(__dirname + '/output.html', newBody, 'utf-8', function(){
        if (err) throw err;
        console.log('done');
    });
});


$(dom.window.window).find('h1')まではブレークさせみてみると
'Array(1) [HTMLHeadingElement]'となってて
DOMそのものは取得できているようなのですが・・・
エラー発生箇所を以下のように書き換えると問題なく完了します

    // Done well(DOM)
    dom.window.document.querySelector("h1").innerHTML = 'Hello World';
    const newBody = dom.window.document.querySelector('html').outerHTML;

(補足)

上記コード内の'$(dom.window.window)'の部分ですが jsdom の仕様を
見ていたりして思いついてやってます。こうしないと、そもそもjQueryが
「jQuery requires a window with a document」のエラーになります

もちろんこのコードに限ったことではないのですが
普通にjQueryが使用できる状況を得るにはどうすればいいでしょうか?

(環境)

OSX HighSierra v.10.13.6
VS CODE v.1.27.2
Node v.8.6.0
jsdom v.12.0.0
jquery v.3.3.1

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+2

単にjQueryでのHTML操作方法が誤っています。

let newBody = $(dom.window.window).find('h1')[0].text('Hello World').parents('html')[0].outerHTML;

これをばらしてみましょうか

let newBody = $(dom.window.window)
  .find('h1')[0] // <-原因はこの[0]
  .text('Hello World')
  .parents('html')[0]
  .outerHTML;

jQueryオブジェクトは、配列アクセスを行うとHTMLのネイティブなエレメントに変換されます。
つまり、この時点でjQueryオブジェクトではなくなります。

続く.text(str).parents('html')はこれ全部jQueryオブジェクト想定ですよね?
最後の.outerHTMLのみHTMLのエレメント想定です

jQueryにはjQueryオブジェクト1個にアクセスする方法としてgetメソッドが存在していたはずです。
.get() - jQueryドキュメント公式

つまりこう書き直せば上手くいくんじゃないですかね?知らんけど。

let newBody = $(dom.window.window)
  .find('h1')
  .get(0)
  .text('Hello World')
  .parents('html')[0]
  .outerHTML;

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/09/16 13:38

    「jQueryオブジェクトは、配列アクセスを行うとHTMLのネイティブなエレメントに変換される」というのは知りませんでした。ありがとうございます。ただ、やってみたのですが以下のエラーになります。
    どうやら「$(dom.window.window) .find('h1')」コレ自体がフェイクjQueryみたいです(w

    TypeError: $(...).find(...).get is not a function

    キャンセル

checkベストアンサー

+1

Node環境(global.documentが定義されていない環境)でrequire('jquery')を実行した場合、戻り値は普段のjQuery関数ではなく、引数にwindowオブジェクトを与えるとjQuery関数を返す関数になるようです。

const jqFactory = require('jquery');
const $ = jqFactory(windowObject);

なので、普段のjQuery関数$を得るには、質問文のコードで言えばdom.windowを指定する必要があります。
また、outerHTMLを取得する行にも修正を加える必要があります。

// 修正前
let newBody = $(dom.window.window).find('h1')[0].text('Hello World').parents('html')[0].outerHTML;

// 修正後
let newBody = $(dom.window.document).find('h1').eq(0).text('Hello World').parents('html')[0].outerHTML;

最終的なコードは下記の通りとなります。(Node v8.11.4で動作確認済)

var jqFactory = require('jquery');
var fs = require('fs');
var jsdom = require('jsdom');
const { JSDOM } = jsdom;

fs.readFile(__dirname + '/input.html', function (err, data) {
    if (err) throw err;
    let body = data.toString();
    const dom = new JSDOM(body);
    const $ = jqFactory(dom.window);

    let newBody = $(dom.window.document).find('h1').eq(0).text('Hello World').parents('html')[0].outerHTML;

    fs.writeFile(__dirname + '/output.html', newBody, 'utf-8', function(){
        if (err) throw err;
        console.log('done');
    });
});

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/09/16 21:59

    getメソッドは配列アクセスと同じくHTMLのネイティブなエレメントが返ってきてしまうので、eqメソッドを使うことになります。 https://api.jquery.com/eq/#eq-index

    キャンセル

  • 2018/09/16 21:59

    ありがとうございます。うまく処理できるようになりました。

    普通(私のリサーチ力では)「戻り値は普段のjQuery関数ではなく」
    facotoryが返ってるって・・・わかりません

    教えてもらえなかったら行きつかなかったと思います(感謝)

    キャンセル

  • 2018/09/16 22:16

    実は私も、この質問について調べる中でjQueryのソースコードを見るまでは知りませんでした。公式の説明もちょうどいいものが見つからなかったので、Web検索だけだと見つからなかったかもしれません。私自身勉強になるよいきっかけになりました。

    キャンセル

+1

getを使う方法が回答されているので別解でも書いときます。

let newBody = $($(dom.window.window).find('h1')[0])
  .text('Hello World')
  .parents('html')[0]
  .outerHTML;


めっちゃ格好悪いですが、これでもいけるはずですね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/09/16 13:40

    これ、私もやってみたのですがやはり以下のエラーになります
    Error: jQuery requires a window with a document

    キャンセル

  • キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.36%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る