<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Vue3 &#8211; ちょいプラ素材</title>
	<atom:link href="https://vitorec.co.jp/choi-plus-sozai/category/%e3%83%96%e3%83%ad%e3%82%b0%e3%82%b5%e3%82%a4%e3%83%88%e3%81%ae%e7%ab%8b%e3%81%a1%e4%b8%8a%e3%81%92%e6%96%b9/vue3/feed/" rel="self" type="application/rss+xml" />
	<link>https://vitorec.co.jp/choi-plus-sozai</link>
	<description>趣味や日々のコトを通して，見つけたモノや出会ったヒト，出かけたトコロを紹介するブログです．</description>
	<lastBuildDate>Fri, 17 Oct 2025 23:33:55 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2024/08/choi-plus-sozai-favicon-150x150.jpg</url>
	<title>Vue3 &#8211; ちょいプラ素材</title>
	<link>https://vitorec.co.jp/choi-plus-sozai</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>「Vue 3 Datepicker」やりたいことは何でもできるんじゃない？！</title>
		<link>https://vitorec.co.jp/choi-plus-sozai/%e3%80%8cvue-3-datepicker%e3%80%8d%e3%82%84%e3%82%8a%e3%81%9f%e3%81%84%e3%81%93%e3%81%a8%e3%81%af%e4%bd%95%e3%81%a7%e3%82%82%e3%81%a7%e3%81%8d%e3%82%8b%e3%82%93%e3%81%98%e3%82%83%e3%81%aa%e3%81%84/</link>
					<comments>https://vitorec.co.jp/choi-plus-sozai/%e3%80%8cvue-3-datepicker%e3%80%8d%e3%82%84%e3%82%8a%e3%81%9f%e3%81%84%e3%81%93%e3%81%a8%e3%81%af%e4%bd%95%e3%81%a7%e3%82%82%e3%81%a7%e3%81%8d%e3%82%8b%e3%82%93%e3%81%98%e3%82%83%e3%81%aa%e3%81%84/#comments</comments>
		
		<dc:creator><![CDATA[管理者]]></dc:creator>
		<pubDate>Mon, 25 Jul 2022 03:15:19 +0000</pubDate>
				<category><![CDATA[Vue3]]></category>
		<category><![CDATA[ブログサイトの立ち上げ方]]></category>
		<guid isPermaLink="false">https://vitorec.co.jp/choi-plus-sozai/?p=11120</guid>

					<description><![CDATA[目次 環境Vue 3 Datepickerとは？Vue 3 Datepickerの機能紹介デフォルト状態フォーマットの変更日本語表記にする「秒」を入力できるようにする2つのカレンダーを表示して期間を入力するまとめ 環境  [&#8230;]]]></description>
										<content:encoded><![CDATA[

  <div id="toc" class="toc tnt-number-detail toc-center tnt-number_detail border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-2" checked><label class="toc-title" for="toc-checkbox-2">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">環境</a></li><li><a href="#toc2" tabindex="0">Vue 3 Datepickerとは？</a></li><li><a href="#toc3" tabindex="0">Vue 3 Datepickerの機能紹介</a><ol><li><a href="#toc4" tabindex="0">デフォルト状態</a></li><li><a href="#toc5" tabindex="0">フォーマットの変更</a></li><li><a href="#toc6" tabindex="0">日本語表記にする</a></li><li><a href="#toc7" tabindex="0">「秒」を入力できるようにする</a></li><li><a href="#toc8" tabindex="0">2つのカレンダーを表示して期間を入力する</a></li></ol></li><li><a href="#toc9" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">環境</span></h2>



<p>このページで使用しているフレームワークやライブラリのバージョンは、以下のとおりです。</p>



<figure class="wp-block-table"><table><tbody><tr><td>vue.js</td><td>3.2.37</td></tr><tr><td>Vue 3 Datepicker</td><td>7.2.2</td></tr></tbody></table></figure>



<h2 class="wp-block-heading"><span id="toc2">Vue 3 Datepickerとは？</span></h2>



<p>「<a rel="noopener noreferrer" href="https://vue3datepicker.com/" target="_blank">Vue 3 Datepicker<span class="fa fa-external-link external-icon anchor-icon"></span></a>」は、Vue3で使用できるDate-Time-Pickerライブラリです。</p>



<p>今回、以下の機能を持ったDate-Time-Pickerを探していて見つけたライブラリです。</p>



<ul class="wp-block-list">
<li>日付と時刻が入力できること。</li>



<li>時刻は、「秒」まで入力できること。</li>



<li>日本語表記に対応できること。</li>



<li>モダンなデザインで、使いやすいUIであること。</li>
</ul>



<p>デザインや使い勝手は、好みのわかれるところですが、この「Vue 3 Datepicker」は、何より機能が豊富です。</p>



<p>「やりたいこと、何でもできるじゃん！」と感激したので、是非とも紹介したくなりました。</p>



<h2 class="wp-block-heading"><span id="toc3">Vue 3 Datepickerの機能紹介</span></h2>



<p>「Vue 3 Datepicker」は、とにかく機能が豊富です。<br>全ての機能は、<a rel="noopener noreferrer" href="https://vue3datepicker.com/" target="_blank">公式のドキュメント<span class="fa fa-external-link external-icon anchor-icon"></span></a>を見てもらうとして、ここでは、一部の機能と実際のソースコードを紹介します。</p>



<h3 class="wp-block-heading"><span id="toc4">デフォルト状態</span></h3>



<p>まずは、デフォルトの状態です。<br>厳密には、デフォルト状態に<strong>placeholder</strong>を追加しています。<br><br>下のテキストボックスをクリックして、実際の日時を入力してみてください。</p>



<div id="app-default">
    <datepicker placeholder="ここをクリックして日時を入力" v-model="date"></datepicker>
</div>

<script>
    Vue.createApp({
        components: { Datepicker: VueDatePicker },
        data() {
            return { date: Vue.ref() };
        },
    }).mount("#app-default");
</script>



<div class="wp-block-cocoon-blocks-micro-text micro-text micro-copy micro-top"><span class="micro-text-content micro-content"><span class="micro-text-icon micro-icon fab-edit"></span>コード</span></div>



<div class="hcb_wrap"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;div id=&quot;app-default&quot;&gt;
    &lt;datepicker
        placeholder=&quot;ここをクリックして日時を入力&quot;
        v-model=&quot;date&quot;
    &gt;&lt;/datepicker&gt;
&lt;/div&gt;

&lt;script&gt;
    Vue.createApp({
        components: { Datepicker: VueDatePicker },
        data() {
            return { date: Vue.ref() };
        },
    }).mount(&quot;#app-default&quot;);
&lt;/script&gt;</code></pre></div>



<h3 class="wp-block-heading"><span id="toc5">フォーマットの変更</span></h3>



<p>デフォルトの状態では、入力した日時が「MM/DD/YYYY, HH:mm」のフォーマットで表示されます。<br>このフォーマットを「YYYY-MM-DD HH:mm:ss」に変更します。</p>



<div id="app-format">
    <datepicker placeholder="ここをクリックして日時を入力" v-model="date" v-bind:format="format"></datepicker>
</div>

<script>
    Vue.createApp({
        components: { Datepicker: VueDatePicker },
        data() {
            return {
                date: Vue.ref(),
                format: (date) => {
                    const year = date.getFullYear();
                    const month = String(date.getMonth() + 1).padStart(2, "0");
                    const day = String(date.getDate()).padStart(2, "0");
                    const hours = String(date.getHours()).padStart(2, "0");
                    const minutes = String(date.getMinutes()).padStart(2, "0");
                    const seconds = String(date.getSeconds()).padStart(2, "0");

                    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
                },
            };
        },
    }).mount("#app-format");
</script>



<div class="wp-block-cocoon-blocks-micro-text micro-text micro-copy micro-top"><span class="micro-text-content micro-content"><span class="micro-text-icon micro-icon fab-edit"></span>コード</span></div>



<div class="hcb_wrap"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;div id=&quot;app-format&quot;&gt;
    &lt;datepicker
        placeholder=&quot;ここをクリックして日時を入力&quot;
        v-model=&quot;date&quot;
        v-bind:format=&quot;format&quot;
    &gt;&lt;/datepicker&gt;
&lt;/div&gt;

&lt;script&gt;
    Vue.createApp({
        components: { Datepicker: VueDatePicker },
        data() {
            return {
                date: Vue.ref(),
                format: (date) =&gt; {
                    const year = date.getFullYear();
                    const month = String(date.getMonth() + 1).padStart(2, &quot;0&quot;);
                    const day = String(date.getDate()).padStart(2, &quot;0&quot;);
                    const hours = String(date.getHours()).padStart(2, &quot;0&quot;);
                    const minutes = String(date.getMinutes()).padStart(2, &quot;0&quot;);
                    const seconds = String(date.getSeconds()).padStart(2, &quot;0&quot;);

                    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
                },
            };
        },
    }).mount(&quot;#app-format&quot;);
&lt;/script&gt;
</code></pre></div>



<h3 class="wp-block-heading"><span id="toc6">日本語表記にする</span></h3>



<p>&lt;datepicker&gt;タグに<strong>locale="jp"</strong>を追加するだけで、曜日が日本語表記になります。</p>



<p><strong>cancel-text="キャンセル"</strong>、<strong>select-text="OK"</strong>も追加して、”Cancel”を”キャンセル”、”Select”を”OK”に変更します。</p>



<p>「月」の数字の後ろに”月”、「年」の数字の後ろに”年”の文字を表示するには、<br><strong>&lt;template year="{ value }"&gt; {{ value }}年&gt;&lt;/template&gt;</strong><br>を追加します。</p>



<div class="wp-block-cocoon-blocks-icon-box common-icon-box block-box alert-box">
<p>Vue 3 Datepickerのバージョン5.x.xまでは、&lt;template>タグの<span class="bold-red">赤字</span>部分を下記のとおり<span class="bold-red">year</span>にする必要がありました。<br><br><strong>&lt;template year="{ <span class="bold-red">year</span> }"> {{ <span class="bold-red">year</span> }}年>&lt;/template></strong><br><br>このように、Vue 3 Datepickerは、バージョンによって仕様が大きく変わりますので、注意が必要です。</p>
</div>



<p>これ以降、実際のコードは、&lt;datepicker&gt;…&lt;/datepicker&gt;タグの部分のみが変更になりますので、&lt;datepicker&gt;…&lt;/datepicker&gt;タグ部分のみを掲載します。</p>



<div id="app-jp">
    <datepicker placeholder="ここをクリックして日時を入力" v-model="date" v-bind:format="format" locale="jp" cancel-text="キャンセル" select-text="OK">
        <template #year="{ value }"> {{ value }}年 </template>
    </datepicker>
</div>

<script>
    Vue.createApp({
        components: { Datepicker: VueDatePicker },
        data() {
            return {
                date: Vue.ref(),
                format: (date) => {
                    const year = date.getFullYear();
                    const month = String(date.getMonth() + 1).padStart(2, "0");
                    const day = String(date.getDate()).padStart(2, "0");
                    const hours = String(date.getHours()).padStart(2, "0");
                    const minutes = String(date.getMinutes()).padStart(2, "0");
                    const seconds = String(date.getSeconds()).padStart(2, "0");

                    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
                },
            };
        },
    }).mount("#app-jp");
</script>



<div class="wp-block-cocoon-blocks-micro-text micro-text micro-copy micro-top"><span class="micro-text-content micro-content"><span class="micro-text-icon micro-icon fab-edit"></span>コード</span></div>



<div class="hcb_wrap"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>    &lt;datepicker
        placeholder=&quot;ここをクリックして日時を入力&quot;
        v-model=&quot;date&quot;
        v-bind:format=&quot;format&quot;
        locale=&quot;jp&quot;
        cancel-text=&quot;キャンセル&quot;
        select-text=&quot;OK&quot;
    &gt;
        &lt;template #year=&quot;{ value }&quot;&gt; {{ value }}年 &lt;/template&gt;
    &lt;/datepicker&gt;</code></pre></div>



<h3 class="wp-block-heading"><span id="toc7">「秒」を入力できるようにする</span></h3>



<p>&lt;datepicker&gt;タグに<strong>enable-seconds</strong>を追加するだけで、時刻入力で「秒」も入力できるようになります。</p>



<div id="app-seconds">
    <datepicker placeholder="ここをクリックして日時を入力" v-model="date" v-bind:format="format" locale="jp" cancel-text="キャンセル" select-text="OK" enable-seconds="">
        <template #year="{ value }"> {{ value }}年 </template>
    </datepicker>
</div>

<script>
    Vue.createApp({
        components: { Datepicker: VueDatePicker },
        data() {
            return {
                date: Vue.ref(),
                format: (date) => {
                    const year = date.getFullYear();
                    const month = String(date.getMonth() + 1).padStart(2, "0");
                    const day = String(date.getDate()).padStart(2, "0");
                    const hours = String(date.getHours()).padStart(2, "0");
                    const minutes = String(date.getMinutes()).padStart(2, "0");
                    const seconds = String(date.getSeconds()).padStart(2, "0");

                    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
                },
            };
        },
    }).mount("#app-seconds");
</script>



<div class="wp-block-cocoon-blocks-micro-text micro-text micro-copy micro-top"><span class="micro-text-content micro-content"><span class="micro-text-icon micro-icon fab-edit"></span>コード</span></div>



<div class="hcb_wrap"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>    &lt;datepicker
        placeholder=&quot;ここをクリックして日時を入力&quot;
        v-model=&quot;date&quot;
        v-bind:format=&quot;format&quot;
        locale=&quot;jp&quot;
        cancel-text=&quot;キャンセル&quot;
        select-text=&quot;OK&quot;
        enable-seconds
    &gt;
        &lt;template #year=&quot;{ value }&quot;&gt; {{ value }}年 &lt;/template&gt;
    &lt;/datepicker&gt;</code></pre></div>



<h3 class="wp-block-heading"><span id="toc8">2つのカレンダーを表示して期間を入力する</span></h3>



<p>最後に2つのカレンダーを表示して、期間を入力する例です。<br>&lt;datepicker&gt;タグに<strong>range</strong>と<strong>multi-calendars</strong>を追加します。</p>



<p>日時が格納される変数<strong>date</strong>が配列になるので、<strong>format</strong>関数が少し複雑になります。<br></p>



<div id="app-multi">
    <datepicker placeholder="ここをクリックして日時を入力" v-model="date" v-bind:format="format" locale="jp" cancel-text="キャンセル" select-text="OK" enable-seconds="" range="" multi-calendars="">
        <template #year="{ value }"> {{ value }}年 </template>
    </datepicker>
</div>

<script>
    Vue.createApp({
        components: { Datepicker: VueDatePicker },
        mounted() {
            this.date = [];
        },
        data() {
            return {
                date: Vue.ref(),
                format: (date_array) => {
                    let result = "";
                    date_array.forEach((date, index) => {
                        if (Object.prototype.toString.call(date) == "[object Date]") {
                            const year = date.getFullYear();
                            const month = String(date.getMonth() + 1).padStart(2, "0");
                            const day = String(date.getDate()).padStart(2, "0");
                            const hours = String(date.getHours()).padStart(2, "0");
                            const minutes = String(date.getMinutes()).padStart(2, "0");
                            const seconds = String(date.getSeconds()).padStart(2, "0");

                            result += `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
                            if (index == 0) {
                                result += ` - `;
                            }
                        }
                    });

                    return result;
                },
            };
        },
    }).mount("#app-multi");
</script>



<div class="wp-block-cocoon-blocks-micro-text micro-text micro-copy micro-top"><span class="micro-text-content micro-content"><span class="micro-text-icon micro-icon fab-edit"></span>コード</span></div>



<div class="hcb_wrap"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;div id=&quot;app-multi&quot;&gt;
    &lt;datepicker
        placeholder=&quot;ここをクリックして日時を入力&quot;
        v-model=&quot;date&quot;
        v-bind:format=&quot;format&quot;
        locale=&quot;jp&quot;
        cancel-text=&quot;キャンセル&quot;
        select-text=&quot;OK&quot;
        enable-seconds
        range
        multi-calendars
    &gt;
        &lt;template #year=&quot;{ value }&quot;&gt; {{ value }}年 &lt;/template&gt;
    &lt;/datepicker&gt;
&lt;/div&gt;

&lt;script&gt;
    Vue.createApp({
        components: { Datepicker: VueDatePicker },
        mounted() {
            this.date = [];
        },
        data() {
            return {
                date: Vue.ref(),
                format: (date_array) =&gt; {
                    let result = &quot;&quot;;
                    date_array.forEach((date, index) =&gt; {
                        if (Object.prototype.toString.call(date) == &quot;[object Date]&quot;) {
                            const year = date.getFullYear();
                            const month = String(date.getMonth() + 1).padStart(2, &quot;0&quot;);
                            const day = String(date.getDate()).padStart(2, &quot;0&quot;);
                            const hours = String(date.getHours()).padStart(2, &quot;0&quot;);
                            const minutes = String(date.getMinutes()).padStart(2, &quot;0&quot;);
                            const seconds = String(date.getSeconds()).padStart(2, &quot;0&quot;);

                            result += `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
                            if (index == 0) {
                                result += ` - `;
                            }
                        }
                    });

                    return result;
                },
            };
        },
    }).mount(&quot;#app-multi&quot;);
&lt;/script&gt;</code></pre></div>



<h2 class="wp-block-heading"><span id="toc9">まとめ</span></h2>



<p>日時入力に関して、やりたいことが何でもできそうな「Vue 3 Datepicker」を紹介しました。</p>



<p>ここで紹介した機能を使って、GPXファイルのタイムスタンプを変更するアプリケーションを作ってみました。</p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-related">

<a href="https://vitorec.co.jp/choi-plus-sozai/gpx%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%81%ae%e3%82%bf%e3%82%a4%e3%83%a0%e3%82%b9%e3%82%bf%e3%83%b3%e3%83%97%e3%82%92%e5%a4%89%e6%9b%b4%e3%81%99%e3%82%8b/" title="GPXファイルのタイムスタンプを変更する" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/07/ca409b1593a4491d18292e29ca6b6786-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/07/ca409b1593a4491d18292e29ca6b6786-160x90.png 160w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/07/ca409b1593a4491d18292e29ca6b6786-120x68.png 120w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/07/ca409b1593a4491d18292e29ca6b6786-320x180.png 320w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">GPXファイルのタイムスタンプを変更する</div><div class="blogcard-snippet internal-blogcard-snippet">GPXファイルのタイムスタンプを変更するツールを作成しました。「Vue 3 Datepicker」で開始日時/終了日時を指定して、GPXファイルのタイムスタンプを簡単に変更できます。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://vitorec.co.jp/choi-plus-sozai" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">vitorec.co.jp</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2022.08.14</div></div></div></div></a>
</div>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>
]]></content:encoded>
					
					<wfw:commentRss>https://vitorec.co.jp/choi-plus-sozai/%e3%80%8cvue-3-datepicker%e3%80%8d%e3%82%84%e3%82%8a%e3%81%9f%e3%81%84%e3%81%93%e3%81%a8%e3%81%af%e4%bd%95%e3%81%a7%e3%82%82%e3%81%a7%e3%81%8d%e3%82%8b%e3%82%93%e3%81%98%e3%82%83%e3%81%aa%e3%81%84/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>WordPressの投稿にガントチャートを実装する</title>
		<link>https://vitorec.co.jp/choi-plus-sozai/wordpress%e3%81%ae%e6%8a%95%e7%a8%bf%e3%81%ab%e3%82%ac%e3%83%b3%e3%83%88%e3%83%81%e3%83%a3%e3%83%bc%e3%83%88%e3%82%92%e5%ae%9f%e8%a3%85%e3%81%99%e3%82%8b/</link>
					<comments>https://vitorec.co.jp/choi-plus-sozai/wordpress%e3%81%ae%e6%8a%95%e7%a8%bf%e3%81%ab%e3%82%ac%e3%83%b3%e3%83%88%e3%83%81%e3%83%a3%e3%83%bc%e3%83%88%e3%82%92%e5%ae%9f%e8%a3%85%e3%81%99%e3%82%8b/#respond</comments>
		
		<dc:creator><![CDATA[管理者]]></dc:creator>
		<pubDate>Fri, 10 Jun 2022 15:00:00 +0000</pubDate>
				<category><![CDATA[Vue3]]></category>
		<category><![CDATA[ブログサイトの立ち上げ方]]></category>
		<guid isPermaLink="false">https://vitorec.co.jp/choi-plus-sozai/?p=10848</guid>

					<description><![CDATA[目次 環境frappe-ganttとは？実装したガントチャートガントチャートの編集方法工数グラフまとめ 環境 このページで使用しているフレームワークやライブラリのバージョンは、以下のとおりです。 vue.js 3.2.3 [&#8230;]]]></description>
										<content:encoded><![CDATA[

  <div id="toc" class="toc tnt-number-detail toc-center tnt-number_detail border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-4" checked><label class="toc-title" for="toc-checkbox-4">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">環境</a></li><li><a href="#toc2" tabindex="0">frappe-ganttとは？</a></li><li><a href="#toc3" tabindex="0">実装したガントチャート</a><ol><li><a href="#toc4" tabindex="0">ガントチャートの編集方法</a></li><li><a href="#toc5" tabindex="0">工数グラフ</a></li></ol></li><li><a href="#toc6" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">環境</span></h2>



<p>このページで使用しているフレームワークやライブラリのバージョンは、以下のとおりです。</p>



<figure class="wp-block-table"><table><tbody><tr><td>vue.js</td><td>3.2.31</td></tr><tr><td>vue3-sfc-loader</td><td>0.8.4</td></tr><tr><td>frappe-gantt</td><td>0.6.1をベースに機能拡張</td></tr><tr><td>moment</td><td>2.29.3</td></tr><tr><td>sweetalert2</td><td>11.4.17</td></tr><tr><td>vue-select</td><td>4.0.0-beta.3</td></tr><tr><td>@lk77/vue3-color</td><td>3.0.6</td></tr><tr><td>encoding-japanese</td><td>2.0.0</td></tr></tbody></table></figure>



<h2 class="wp-block-heading"><span id="toc2">frappe-ganttとは？</span></h2>



<p>「<a href="https://github.com/frappe/gantt">frappe-gantt<span class="fa fa-external-link external-icon anchor-icon"></span></a>」は、マウスでドラッグしてグラフィカルに編集できるガントチャートのJavaScriptライブラリです。<br>センスの良いデザイン、わかりやすいユーザーインターフェースが魅力的です。</p>



<p>ただ、アップデートが停滞気味で、機能的にも足りない部分があるので、「frappe-gantt」を独自に機能拡張したライブラリを作成することにしました。</p>



<p>追加した機能は、以下のとおりです。</p>



<ul class="wp-block-list">
<li>タスクの担当者入力</li>



<li>タスクの工数配分入力</li>



<li>タスクや進捗度の色の編集</li>



<li>タスクに入力した担当者 / 工数配分を基に、積み上げ工数グラフを表示</li>
</ul>



<p>作成したJavaScriptライブラリを「Vue3.x」から利用して、WordPressの投稿にガントチャートを実装します。</p>



<h2 class="wp-block-heading"><span id="toc3">実装したガントチャート</span></h2>



<p>実装したガントチャートです。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div id="spinner" uk-spinner="ratio: 2"></div>



<script src="https://cdn.jsdelivr.net/npm/vue@3.2.31/dist/vue.global.js"></script>

<!-- Vue3 datepicker -->
<!-- <script src="https://unpkg.com/@vuepic/vue-datepicker@latest"></script> -->
<!-- <link rel="stylesheet" href="https://unpkg.com/@vuepic/vue-datepicker@latest/dist/main.css"> -->
<script src="https://cdn.jsdelivr.net/npm/@vuepic/vue-datepicker@7.2.2/dist/vue-datepicker.iife.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@vuepic/vue-datepicker@7.2.2/dist/main.css">

<div id="app"></div>

<script type="module">
    ////////////////////////////////////////////////////////////////////////////////
    // vue3-sfc-loader モジュール
    ////////////////////////////////////////////////////////////////////////////////
    import { loadModule } from "https://cdn.jsdelivr.net/npm/vue3-sfc-loader@0.8.4/dist/vue3-sfc-loader.esm.js";

    ////////////////////////////////////////////////////////////////////////////////
    // vue3-sfc-loader オプション
    // SFCファイルから外部のモジュールをimportできるオプション
    // 参考：https://github.com/FranckFreiburger/vue3-sfc-loader/issues/14#issuecomment-908849863
    ////////////////////////////////////////////////////////////////////////////////
    const vue3_sfc_loader_options = {
        moduleCache: { vue: Vue },
        getFile(url) {
            url = /.*?\.js|.mjs|.css|.less|.vue$/.test(url)
                ? url
                : `${url}.vue`;
            const type = /.*?\.js|.mjs$/.test(url)
                ? ".mjs"
                : /.*?\.vue$/.test(url)
                ? ".vue"
                : /.*?\.css$/.test(url)
                ? ".css"
                : ".vue";
            const getContentData = (asBinary) =>
                fetch(url).then((res) =>
                    !res.ok
                        ? Promise.reject(url)
                        : asBinary
                        ? res.arrayBuffer()
                        : res.text()
                );
            return { getContentData: getContentData, type: type };
        },
        addStyle(textContent) {
            let styleElement = document.createElement("style");
            document.head.insertBefore(
                Object.assign(styleElement, { textContent }),
                document.head.getElementsByTagName("style")[0] || null
            );
        },
        handleModule(type, getContentData, path, options) {
            switch (type) {
                case ".css":
                    return options.addStyle(getContentData(false));
                case ".less":
                    console.error(".......");
            }
        },
        log(type, ...args) {
            console.log(type, ...args);
        },
    };

    ////////////////////////////////////////////////////////////////////////////////
    // Vue.js アプリケーションインスタンス
    ////////////////////////////////////////////////////////////////////////////////
    const app = Vue.createApp({
        components: {
            "vue-gantt": Vue.defineAsyncComponent(() =>
                loadModule(
                    "../wp-content/themes/cocoon-child-master/vue-components/VueGantt.vue?version=1-1-5",
                    vue3_sfc_loader_options
                )
            ),
        },
        template: `<vue-gantt />`,
    });
    app.mount("#app");
</script>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<p>初回は、本日の位置に［初期タスク］が1つ配置されます。<br>スクロールバーを本日の位置に動かしてください。<br>この状態から、ガントチャートを編集していきます。</p>



<p>次回以降は、前回の編集途中のガントチャートが自動的に読み込まれます。</p>



<div class="wp-block-cocoon-blocks-icon-box common-icon-box block-box alert-box">
<p>・別のPCやブラウザを使った場合<br />・ブラウザのデータをクリアした場合<br />は、前回の編集途中のガントチャートや一時保存したガントチャートを読み込むことができなくなります。<br />重要なガントチャートは、ローカルファイルにダウンロードしてください。</p>
<p>キーボード操作が必要なため、スマートフォンやタブレットでは、正しく編集できません。</p>
</div>



<h3 class="wp-block-heading"><span id="toc4">ガントチャートの編集方法</span></h3>



<ul>
    <li>
        <strong>タスク情報を変更する</strong
        ><br />タスクをダブルクリックすると、タスク情報を編集するダイアログが表示されます。<br />
        ダイアログにタスク情報を入力し、<span class="swal2-confirm-text"
            >OK</span
        >
        ボタンを押します。<br /><br />
        タスク名だけは、入力が<b><span style="color: red">必須</span></b
        >の項目です。<br /><br />
        <!-- タスクの開始日時 / 終了日時のボックスをクリックするとカレンダー /
        時計のユーザーインターフェースが表示され、開始日時 /
        終了日時を変更できます。<br /><br /> -->
        タスクの詳細は、複数行テキスト、HTMLタグも入力できます。<br /><br />
        担当者は、そのタスクを担当する人の情報（名前やID、メールアドレスなど）を入力します。<br /><br />
        工数配分は、そのタスクに配分する工数の割合を入力します。<br /><br />
        プログレスの色 /
        タスクバーの色を指定したい場合は、色指定ボタン（小さい長方形
        <span class="color-button-text">&nbsp;</span>
        ）を押し、カラーピッカーを起動して色を選びます。<br />色指定ボタンを押すたびに、カラーピッカーの表示
        / 非表示が切り替わります。<br />　
    </li>
    <li>
        <strong>タスクの開始日 / 終了日を変更する</strong
        ><br />タスクにマウスカーソルを合わせると、タスクの左端 /
        右端にハンドルが表示されます。<br />左端 /
        右端のハンドルをドラッグし、タスクの開始日 / 終了日を変更します。<br /><br />タスクを左右にドラッグすると、開始日
        / 終了日の間隔を維持したまま、タスクの日程を変更できます。<br />
        ［Shift］キーを押しながら左右にドラッグすると、移動方向は左右のみに固定され、上下の位置は変わりません。<br /><!-- <br />
        タスク情報を編集するダイアログでも、カレンダー /
        時計のユーザーインターフェースを使って、タスクの開始日時 /
        終了日時を変更できます。<br /> -->　
    </li>
    <li>
        <strong>タスクの進捗度を変更する</strong
        ><br />タスクにマウスカーソルを合わせると、三角形のハンドルが表示されます。<br />三角形のハンドルをドラッグし、タスクの進捗度を変更します。<br />　
    </li>
    <li>
        <strong style="text-align: -webkit-match-parent"
            >タスクを追加する</strong
        ><br /><span class="gantt-button-text"
            ><i class="fa-solid fa-square-plus"></i> タスクを追加</span
        >
        ボタンを押すと、新規のタスク情報を入力するダイアログが表示されます。<br />
        ダイアログにタスク情報を入力し、<span class="swal2-confirm-text"
            >OK</span
        >
        ボタンを押すと、新しいタスクが一番下に追加されます。<br /><br />
        タスク名だけは、入力が<b><span style="color: red">必須</span></b
        >の項目です。<br />　
    </li>
    <li>
        <strong>タスクを削除する</strong
        ><br />タスクを右クリックすると、タスクの削除を確認するダイアログが表示されます。<br />
        ダイアログの
        <span class="swal2-confirm-text">OK</span>
        ボタンを押すと、選択したタスクが削除されます。<br />　
    </li>
    <li>
        <strong>タスクの依存関係（親子関係）を変更する</strong
        ><br />［Alt］キーを押したまま、「親タスク」をクリックします。<br />赤い矢印が表示されます。<br />その後、依存関係を設定したい「子タスク」をクリックします。<br />「親タスク」から「子タスク」に矢印がつながり、依存関係が設定されます。<br /><br />既に、依存関係が設定されている場合は、依存関係が解除されます。<br />　
    </li>
    <li>
        <strong style="text-align: -webkit-match-parent"
            >タスクの上下位置を変更する</strong
        ><br />タスクを上下にドラッグすると、タスクの上下位置を変更できます。<br />
        ［Shift］キーを押しながら上下にドラッグすると、移動方向は上下のみに固定され、左右の位置は変わりません。<br /><br />
        「子タスク」を「親タスク」の上に移動することはできません。<br />ドラッグ後のタスクの位置は、「親タスク」「子タスク」の上下関係を優先して調整されます。<br /><br />
        <div
            class="gantt-free-index"
            style="margin-left: 1.5em; margin-bottom: 0.5em; font-size: 0.95em"
        >
            <input
                type="checkbox"
                id="free-index"
                class="gantt-checkbox"
                checked
            />
            <label for="free-index" class="gantt-label"
                >タスクの上下位置を自由に配置</label
            >
        </div>
        を有効にした状態でタスクを上下にドラッグすると、上下位置を自由に変更できます。<br />
        この状態では、「親タスク」「子タスク」の関係も無視され、タスクを移動した後の上下位置の整列も行いません。<br />　
    </li>
    <li>
        <strong>ビューモードを変更する</strong><br /><span
            class="gantt-button-text"
            >日</span
        >
        <span class="gantt-button-text">週</span>
        <span class="gantt-button-text">月</span>
        ボタンを押して、ビューモードを変更します。<br />　
    </li>
    <li>
        <strong>ガントチャートをリセットする</strong><br /><span
            class="gantt-button-text"
            ><i class="fa-solid fa-trash"></i> リセット</span
        >
        ボタンを押すと、ガントチャートのリセットを確認するダイアログが表示されます。<br />
        ダイアログの
        <span class="swal2-confirm-text">OK</span>
        ボタンを押すと、ガントチャートを初期状態にリセットします。<br />　
    </li>
    <li>
        <strong>ガントチャートを保存 / 読込む</strong><br /><span
            class="gantt-button-text"
            ><i class="fa-solid fa-right-to-bracket"></i> 保存</span
        >
        ボタンを押すと、ガントチャートの保存を確認するダイアログが表示されます。<br />
        ダイアログの
        <span class="swal2-confirm-text">OK</span>
        ボタンを押すと、作成中のガントチャートを自分の使っているブラウザに一時的に保存します。<br /><br /><span
            class="gantt-button-text"
            ><i class="fa-solid fa-right-from-bracket"></i> 読込み</span
        >
        ボタンを押すと、ガントチャートの読込みを確認するダイアログが表示されます。<br />
        ダイアログの
        <span class="swal2-confirm-text">OK</span>
        ボタンを押すと、保存したガントチャートを読込みます。<br /><br />ブラウザを閉じても、保存したガントチャートはブラウザに残ります。<br />　
    </li>
    <li>
        <strong>ガントチャートをダウンロード / アップロードする</strong
        ><br /><span class="gantt-button-text"
            ><i class="fa-solid fa-file-arrow-down"></i> ダウンロード</span
        >
        ボタンを押すと、作成中のガントチャートをローカルファイルにダウンロードできます。<br /><br /><span
            class="gantt-button-text"
            ><i class="fa-solid fa-file-arrow-up"></i> アップロード</span
        >
        ボタンを押し、ダウンロードしたガントチャートファイルを指定すると、このファイルがアップロードされ、ガントチャートが更新されます。
    </li>
</ul>



<h3 class="wp-block-heading"><span id="toc5">工数グラフ</span></h3>



<ul>
    <li>
        <strong>タスク情報を変更する</strong
        ><br />タスクをダブルクリックすると、タスク情報を編集するダイアログが表示されます。<br />
        ダイアログにタスク情報を入力し、<span class="swal2-confirm-text"
            >OK</span
        >
        ボタンを押します。<br /><br />
        タスク名だけは、入力が<b><span style="color: red">必須</span></b
        >の項目です。<br /><br />
        タスクの開始日時 / 終了日時のボックスをクリックするとカレンダー /
        時計のユーザーインターフェースが表示され、開始日時 /
        終了日時を変更できます。<br /><br />
        タスクの詳細は、複数行テキスト、HTMLタグも入力できます。<br /><br />
        担当者は、そのタスクを担当する人の情報（名前やID、メールアドレスなど）を入力します。<br /><br />
        工数配分は、そのタスクに配分する工数の割合を入力します。<br /><br />
        プログレスの色 /
        タスクバーの色を指定したい場合は、色指定ボタン（小さい長方形
        <span class="color-button-text">&nbsp;</span>
        ）を押し、カラーピッカーを起動して色を選びます。<br />色指定ボタンを押すたびに、カラーピッカーの表示
        / 非表示が切り替わります。<br />　
    </li>
    <li>
        <strong>タスクの開始日 / 終了日を変更する</strong
        ><br />タスクにマウスカーソルを合わせると、タスクの左端 /
        右端にハンドルが表示されます。<br />左端 /
        右端のハンドルをドラッグし、タスクの開始日 / 終了日を変更します。<br /><br />タスクを左右にドラッグすると、開始日
        / 終了日の間隔を維持したまま、タスクの日程を変更できます。<br />
        ［Shift］キーを押しながら左右にドラッグすると、移動方向は左右のみに固定され、上下の位置は変わりません。<br /><br />
        タスク情報を編集するダイアログでも、カレンダー /
        時計のユーザーインターフェースを使って、タスクの開始日時 /
        終了日時を変更できます。<br />　
    </li>
    <li>
        <strong>タスクの進捗度を変更する</strong
        ><br />タスクにマウスカーソルを合わせると、三角形のハンドルが表示されます。<br />三角形のハンドルをドラッグし、タスクの進捗度を変更します。<br />　
    </li>
    <li>
        <strong style="text-align: -webkit-match-parent"
            >タスクを追加する</strong
        ><br /><span class="gantt-button-text"
            ><i class="fa-solid fa-square-plus"></i> タスクを追加</span
        >
        ボタンを押すと、新規のタスク情報を入力するダイアログが表示されます。<br />
        ダイアログにタスク情報を入力し、<span class="swal2-confirm-text"
            >OK</span
        >
        ボタンを押すと、新しいタスクが一番下に追加されます。<br /><br />
        タスク名だけは、入力が<b><span style="color: red">必須</span></b
        >の項目です。<br />　
    </li>
    <li>
        <strong>タスクを削除する</strong
        ><br />タスクを右クリックすると、タスクの削除を確認するダイアログが表示されます。<br />
        ダイアログの
        <span class="swal2-confirm-text">OK</span>
        ボタンを押すと、選択したタスクが削除されます。<br />　
    </li>
    <li>
        <strong>タスクの依存関係（親子関係）を変更する</strong
        ><br />［Alt］キーを押したまま、「親タスク」をクリックします。<br />赤い矢印が表示されます。<br />その後、依存関係を設定したい「子タスク」をクリックします。<br />「親タスク」から「子タスク」に矢印がつながり、依存関係が設定されます。<br /><br />既に、依存関係が設定されている場合は、依存関係が解除されます。<br />　
    </li>
    <li>
        <strong style="text-align: -webkit-match-parent"
            >タスクの上下位置を変更する</strong
        ><br />タスクを上下にドラッグすると、タスクの上下位置を変更できます。<br />
        ［Shift］キーを押しながら上下にドラッグすると、移動方向は上下のみに固定され、左右の位置は変わりません。<br /><br />
        「子タスク」を「親タスク」の上に移動することはできません。<br />ドラッグ後のタスクの位置は、「親タスク」「子タスク」の上下関係を優先して調整されます。<br /><br />
        <div
            class="gantt-free-index"
            style="margin-left: 1.5em; margin-bottom: 0.5em; font-size: 0.95em"
        >
            <input
                type="checkbox"
                id="free-index"
                class="gantt-checkbox"
                checked
            />
            <label for="free-index" class="gantt-label"
                >タスクの上下位置を自由に配置</label
            >
        </div>
        を有効にした状態でタスクを上下にドラッグすると、上下位置を自由に変更できます。<br />
        この状態では、「親タスク」「子タスク」の関係も無視され、タスクを移動した後の上下位置の整列も行いません。<br />　
    </li>
    <li>
        <strong>ビューモードを変更する</strong><br /><span
            class="gantt-button-text"
            >日</span
        >
        <span class="gantt-button-text">週</span>
        <span class="gantt-button-text">月</span>
        ボタンを押して、ビューモードを変更します。<br />　
    </li>
    <li>
        <strong>ガントチャートをリセットする</strong><br /><span
            class="gantt-button-text"
            ><i class="fa-solid fa-trash"></i> リセット</span
        >
        ボタンを押すと、ガントチャートのリセットを確認するダイアログが表示されます。<br />
        ダイアログの
        <span class="swal2-confirm-text">OK</span>
        ボタンを押すと、ガントチャートを初期状態にリセットします。<br />　
    </li>
    <li>
        <strong>ガントチャートを保存 / 読込む</strong><br /><span
            class="gantt-button-text"
            ><i class="fa-solid fa-right-to-bracket"></i> 保存</span
        >
        ボタンを押すと、ガントチャートの保存を確認するダイアログが表示されます。<br />
        ダイアログの
        <span class="swal2-confirm-text">OK</span>
        ボタンを押すと、作成中のガントチャートを自分の使っているブラウザに一時的に保存します。<br /><br /><span
            class="gantt-button-text"
            ><i class="fa-solid fa-right-from-bracket"></i> 読込み</span
        >
        ボタンを押すと、ガントチャートの読込みを確認するダイアログが表示されます。<br />
        ダイアログの
        <span class="swal2-confirm-text">OK</span>
        ボタンを押すと、保存したガントチャートを読込みます。<br /><br />ブラウザを閉じても、保存したガントチャートはブラウザに残ります。<br />　
    </li>
    <li>
        <strong>ガントチャートをダウンロード / アップロードする</strong
        ><br /><span class="gantt-button-text"
            ><i class="fa-solid fa-file-arrow-down"></i> ダウンロード</span
        >
        ボタンを押すと、作成中のガントチャートをローカルファイルにダウンロードできます。<br /><br /><span
            class="gantt-button-text"
            ><i class="fa-solid fa-file-arrow-up"></i> アップロード</span
        >
        ボタンを押し、ダウンロードしたガントチャートファイルを指定すると、このファイルがアップロードされ、ガントチャートが更新されます。
    </li>
</ul>



<h2 class="wp-block-heading"><span id="toc6">まとめ</span></h2>



<p>「frappe-gantt」を独自に機能拡張したJavaScriptライブラリを作成し、WordPressの投稿にガントチャートを実装しました。</p>



<p>ガントチャートを使うと、視覚的に業務計画を立てることができます。<br>また、進捗度も変更できるので、業務の進み具合いもビジュアルに把握しやすくなります。</p>



<p>タスクに担当者と工数配分を入力すれば、積み上げ工数グラフで、担当者ごとの毎日の業務負荷を確認できます。</p>



<p>以下のページは、少し広い画面でガントチャートを編集できます。<br>ちょっとした業務計画の作成に利用ください。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-check">

<a href="https://vitorec.co.jp/choi-plus-sozai/%e3%82%ac%e3%83%b3%e3%83%88%e3%83%81%e3%83%a3%e3%83%bc%e3%83%88/" title="ガントチャート" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/06/Frappe-Gantt-Logo-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/06/Frappe-Gantt-Logo-160x90.png 160w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/06/Frappe-Gantt-Logo-120x68.png 120w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/06/Frappe-Gantt-Logo-320x180.png 320w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">ガントチャート</div><div class="blogcard-snippet internal-blogcard-snippet">ガントチャート編集ページ</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://vitorec.co.jp/choi-plus-sozai" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">vitorec.co.jp</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2024.01.01</div></div></div></div></a>
</div>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>
]]></content:encoded>
					
					<wfw:commentRss>https://vitorec.co.jp/choi-plus-sozai/wordpress%e3%81%ae%e6%8a%95%e7%a8%bf%e3%81%ab%e3%82%ac%e3%83%b3%e3%83%88%e3%83%81%e3%83%a3%e3%83%bc%e3%83%88%e3%82%92%e5%ae%9f%e8%a3%85%e3%81%99%e3%82%8b/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>WordPressの投稿にソートやページネーションの機能を持ったテーブルを実装する</title>
		<link>https://vitorec.co.jp/choi-plus-sozai/wordpress%e3%81%ae%e6%8a%95%e7%a8%bf%e3%81%ab%e3%82%bd%e3%83%bc%e3%83%88%e3%82%84%e3%83%9a%e3%83%bc%e3%82%b8%e3%83%8d%e3%83%bc%e3%82%b7%e3%83%a7%e3%83%b3%e3%81%ae%e6%a9%9f%e8%83%bd%e3%82%92%e6%8c%81/</link>
					<comments>https://vitorec.co.jp/choi-plus-sozai/wordpress%e3%81%ae%e6%8a%95%e7%a8%bf%e3%81%ab%e3%82%bd%e3%83%bc%e3%83%88%e3%82%84%e3%83%9a%e3%83%bc%e3%82%b8%e3%83%8d%e3%83%bc%e3%82%b7%e3%83%a7%e3%83%b3%e3%81%ae%e6%a9%9f%e8%83%bd%e3%82%92%e6%8c%81/#respond</comments>
		
		<dc:creator><![CDATA[管理者]]></dc:creator>
		<pubDate>Sun, 24 Apr 2022 03:05:42 +0000</pubDate>
				<category><![CDATA[Vue3]]></category>
		<category><![CDATA[ブログサイトの立ち上げ方]]></category>
		<guid isPermaLink="false">https://vitorec.co.jp/choi-plus-sozai/?p=10802</guid>

					<description><![CDATA[目次 環境vue-good-table-nextとは？テーブル用ライブラリの比較WordPressの投稿でvue-good-table-nextを使う“table_library_comparison_table.vue [&#8230;]]]></description>
										<content:encoded><![CDATA[

  <div id="toc" class="toc tnt-number-detail toc-center tnt-number_detail border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-6" checked><label class="toc-title" for="toc-checkbox-6">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">環境</a></li><li><a href="#toc2" tabindex="0">vue-good-table-nextとは？</a></li><li><a href="#toc3" tabindex="0">テーブル用ライブラリの比較</a></li><li><a href="#toc4" tabindex="0">WordPressの投稿でvue-good-table-nextを使う</a><ol><li><a href="#toc5" tabindex="0">“table_library_comparison_table.vue”の中身</a></li></ol></li><li><a href="#toc6" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">環境</span></h2>



<p>このページで使用しているフレームワークやライブラリのバージョンは、以下のとおりです。</p>



<figure class="wp-block-table"><table><tbody><tr><td>vue.js</td><td>3.2.31</td></tr><tr><td>vue3-sfc-loader</td><td>0.8.4</td></tr><tr><td>vue-good-table-next</td><td>0.1.0</td></tr></tbody></table></figure>



<h2 class="wp-block-heading"><span id="toc2">vue-good-table-nextとは？</span></h2>



<p>「<a rel="noopener noreferrer" href="https://borisflesch.github.io/vue-good-table-next/" target="_blank">vue-good-table-next<span class="fa fa-external-link external-icon anchor-icon"></span></a>」は、ソート、ページネーション、フィルターなどの機能をもったテーブルを実装できるVueライブラリです。<br>「vue-good-table-next」は、「Vue2.x」で動作する「vue-good-table」を「Vue3.x」に対応させたバージョンです。<br><a rel="noopener noreferrer" href="https://github.com/borisflesch/vue-good-table-next/" target="_blank">GitHub<span class="fa fa-external-link external-icon anchor-icon"></span></a>（updatedショートコードは投稿・固定ページ以外では利用できません。時点）の「vue-good-table-next」バージョンは「0.1.0」で、"README"にも以下の注意書きがあります。</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>This project is a port of Vue-good-table for Vue 3.x. The current version is stable enough to start developing new projects but work is still in progress and changes could be made in the short-term. Thus the project is not yet intended to be used in a production environment.</p></blockquote>



<p>ただ、基本的な動作は安定しているようです。</p>



<h2 class="wp-block-heading"><span id="toc3">テーブル用ライブラリの比較</span></h2>



<p>多機能なテーブルを実装するためのライブラリやプラグインは、以下のようにいろいろ提供されています。</p>



<ul class="wp-block-list"><li><a href="https://borisflesch.github.io/vue-good-table-next/">vue-good-table-next<span class="fa fa-external-link external-icon anchor-icon"></span></a></li><li><a href="https://matanya.gitbook.io/vue-tables-2/">vue-tables2（v-tables3）<span class="fa fa-external-link external-icon anchor-icon"></span></a></li><li><a href="https://www.vuetable.com/">Vuetable-2<span class="fa fa-external-link external-icon anchor-icon"></span></a></li><li><a href="https://gridjs.io/">Grid.js<span class="fa fa-external-link external-icon anchor-icon"></span></a></li></ul>



<p></p>



<p>この記事では「vue-good-table-next」を紹介しますが、各種のライブラリの特徴を比較表にまとめました。（updatedショートコードは投稿・固定ページ以外では利用できません。時点）<br>なお、この比較表は、「vue-good-table-next」をインポートしたSFCで表示しています。</p>



<script src="https://cdn.jsdelivr.net/npm/vue@3.2.31/dist/vue.global.js"></script>

<div id="app"></div>

<script type="module">
    ////////////////////////////////////////////////////////////////////////////////
    // vue3-sfc-loader モジュール
    ////////////////////////////////////////////////////////////////////////////////
    import { loadModule } from "https://cdn.jsdelivr.net/npm/vue3-sfc-loader@0.8.4/dist/vue3-sfc-loader.esm.js";

    ////////////////////////////////////////////////////////////////////////////////
    // vue3-sfc-loader オプション
    // SFCファイルから外部のモジュールをimportできるオプション
    // 参考：https://github.com/FranckFreiburger/vue3-sfc-loader/issues/14#issuecomment-908849863
    ////////////////////////////////////////////////////////////////////////////////
    const vue3_sfc_loader_options = {
        moduleCache: { vue: Vue },
        getFile(url) {
            url = /.*?\.js|.mjs|.css|.less|.vue$/.test(url)
                ? url
                : `${url}.vue`;
            const type = /.*?\.js|.mjs$/.test(url)
                ? ".mjs"
                : /.*?\.vue$/.test(url)
                ? ".vue"
                : /.*?\.css$/.test(url)
                ? ".css"
                : ".vue";
            const getContentData = (asBinary) =>
                fetch(url).then((res) =>
                    !res.ok
                        ? Promise.reject(url)
                        : asBinary
                        ? res.arrayBuffer()
                        : res.text()
                );
            return { getContentData: getContentData, type: type };
        },
        addStyle(textContent) {
            let styleElement = document.createElement("style");
            document.head.insertBefore(
                Object.assign(styleElement, { textContent }),
                document.head.getElementsByTagName("style")[0] || null
            );
        },
        handleModule(type, getContentData, path, options) {
            switch (type) {
                case ".css":
                    return options.addStyle(getContentData(false));
                case ".less":
                    console.error(".......");
            }
        },
        log(type, ...args) {
            console.log(type, ...args);
        },
    };

    ////////////////////////////////////////////////////////////////////////////////
    // Vue.js アプリケーションインスタンス
    ////////////////////////////////////////////////////////////////////////////////
    const app = Vue.createApp({
        components: {
            "table-library-comparison-table": Vue.defineAsyncComponent(() =>
                loadModule(
                    "../wp-content/themes/cocoon-child-master/vue-components/table_library_comparison_table.vue",
                    vue3_sfc_loader_options
                )
            ),
        },
        template: `<table-library-comparison-table />`,
    });
    app.mount("#app");
</script>



<p>カスタマイズの自由度では「vue-tables2（v-tables3）」が優れているのですが、Vue3の対応が不完全なので、総合的に「vue-good-table-next」を選びました。</p>



<h2 class="wp-block-heading"><span id="toc4">WordPressの投稿でvue-good-table-nextを使う</span></h2>



<p>上記の各種ライブラリの比較表の部分には、WordPressのブロックエディタで以下の「カスタム HTML」ブロックを配置しています。</p>



<div class="hcb_wrap html"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue@3.2.31/dist/vue.global.js&quot;&gt;&lt;/script&gt;

&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;

&lt;script type=&quot;module&quot;&gt;
    ////////////////////////////////////////////////////////////////////////////////
    // vue3-sfc-loader モジュール
    ////////////////////////////////////////////////////////////////////////////////
    import { loadModule } from &quot;https://cdn.jsdelivr.net/npm/vue3-sfc-loader@0.8.4/dist/vue3-sfc-loader.esm.js&quot;;

    ////////////////////////////////////////////////////////////////////////////////
    // vue3-sfc-loader オプション
    // SFCファイルから外部のモジュールをimportできるオプション
    // 参考：https://github.com/FranckFreiburger/vue3-sfc-loader/issues/14#issuecomment-908849863
    ////////////////////////////////////////////////////////////////////////////////
    const vue3_sfc_loader_options = {
        moduleCache: { vue: Vue },
        getFile(url) {
            url = /.*?\.js|.mjs|.css|.less|.vue$/.test(url)
                ? url
                : `${url}.vue`;
            const type = /.*?\.js|.mjs$/.test(url)
                ? &quot;.mjs&quot;
                : /.*?\.vue$/.test(url)
                ? &quot;.vue&quot;
                : /.*?\.css$/.test(url)
                ? &quot;.css&quot;
                : &quot;.vue&quot;;
            const getContentData = (asBinary) =&gt;
                fetch(url).then((res) =&gt;
                    !res.ok
                        ? Promise.reject(url)
                        : asBinary
                        ? res.arrayBuffer()
                        : res.text()
                );
            return { getContentData: getContentData, type: type };
        },
        addStyle(textContent) {
            let styleElement = document.createElement(&quot;style&quot;);
            document.head.insertBefore(
                Object.assign(styleElement, { textContent }),
                document.head.getElementsByTagName(&quot;style&quot;)[0] || null
            );
        },
        handleModule(type, getContentData, path, options) {
            switch (type) {
                case &quot;.css&quot;:
                    return options.addStyle(getContentData(false));
                case &quot;.less&quot;:
                    console.error(&quot;.......&quot;);
            }
        },
        log(type, ...args) {
            console.log(type, ...args);
        },
    };

    ////////////////////////////////////////////////////////////////////////////////
    // Vue.js アプリケーションインスタンス
    ////////////////////////////////////////////////////////////////////////////////
    const app = Vue.createApp({
        components: {
            &quot;table-library-comparison-table&quot;: Vue.defineAsyncComponent(() =&gt;
                loadModule(
                    &quot;../wp-content/themes/cocoon-child-master/vue-components/table_library_comparison_table.vue&quot;,
                    vue3_sfc_loader_options
                )
            ),
        },
        template: `&lt;table-library-comparison-table /&gt;`,
    });
    app.mount(&quot;#app&quot;);
&lt;/script&gt;</code></pre></div>



<p>いつものように、「vue3-sfc-loader」で"table_library_comparison_table.vue"を読み込んでいます。</p>



<h3 class="wp-block-heading"><span id="toc5">“table_library_comparison_table.vue”の中身</span></h3>



<p>"table_library_comparison_table.vue"の全体です。</p>



<div class="hcb_wrap html"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;script setup&gt;
////////////////////////////////////////////////////////////////////////////////
// vue-good-table-next モジュール
////////////////////////////////////////////////////////////////////////////////
import { VueGoodTable } from &quot;https://cdn.jsdelivr.net/npm/vue-good-table-next@0.1.0/dist/vue-good-table.cjs.min.js&quot;;

////////////////////////////////////////////////////////////////////////////////
// data
////////////////////////////////////////////////////////////////////////////////
const table_columns = [
    {
        label: &quot;比較項目&quot;,
        field: &quot;comparison_items&quot;,
        thClass: &quot;vgt-center-align vgt-comparison-items&quot;,
        tdClass: &quot;vgt-center-align vgt-comparison-items&quot;,
        sortable: true,
        html: true,
    },
    {
        label: &quot;vue-good-table-next&quot;,
        field: &quot;vue_good_table_next&quot;,
        thClass: &quot;vgt-center-align vgt-vue-good-table-next&quot;,
        tdClass: &quot;vgt-center-align vgt-vue-good-table-next&quot;,
        html: true,
    },
    {
        label: &quot;vue-tables2&quot;,
        field: &quot;vue_tables2&quot;,
        thClass: &quot;vgt-center-align vgt-vue-tables2&quot;,
        tdClass: &quot;vgt-center-align vgt-vue-tables2&quot;,
        html: true,
    },
    {
        label: &quot;Vuetable-2&quot;,
        field: &quot;vuetable_2&quot;,
        thClass: &quot;vgt-center-align vgt-vuetable-2&quot;,
        tdClass: &quot;vgt-center-align vgt-vuetable-2&quot;,
        html: true,
    },
    {
        label: &quot;Grid.js&quot;,
        field: &quot;grid_js&quot;,
        thClass: &quot;vgt-center-align vgt-grid-js&quot;,
        tdClass: &quot;vgt-center-align vgt-grid-js&quot;,
        html: true,
    },
];
const table_rows = Vue.ref([]);
const search_options = {
    enabled: true,
    trigger: &quot;enter&quot;,
    placeholder: &quot;テーブルを検索します&quot;,
};
const sort_options = {
    enabled: false,
};
const pagination_options = {
    enabled: true,
    mode: &quot;pages&quot;,
    perPage: -1, // -1のときは全項目
    position: &quot;top&quot;,
    perPageDropdown: [3, 5],
    dropdownAllowAll: true,
    setCurrentPage: 1,
    nextLabel: &quot;次へ&quot;,
    prevLabel: &quot;前へ&quot;,
    rowsPerPageLabel: &quot;1ページに表示する比較項目数&quot;,
    ofLabel: &quot; / &quot;,
    pageLabel: &quot;ページ&quot;, // for &#39;pages&#39; mode
    allLabel: &quot;全項目&quot;,
};

////////////////////////////////////////////////////////////////////////////////
// onMountedライフサイクルフック
////////////////////////////////////////////////////////////////////////////////
Vue.onMounted(() =&gt; {
    table_rows.value = [
        {
            comparison_items: &quot;Vue3対応&quot;,
            vue_good_table_next: &quot;〇&lt;br&gt;基本的な動作は安定&quot;,
            vue_tables2: &quot;&lt;span style=&#39;font-size: 1.2em;&#39;&gt;△&lt;/span&gt;&lt;br&gt;v-tables3で対応しているが不完全&quot;,
            vuetable_2: &quot;&lt;span style=&#39;font-size: 1.8em;&#39;&gt;×&lt;/span&gt;&quot;,
            grid_js: &quot;〇&lt;br&gt;オリジナルがJavaScriptライブラリなので、Vue3のコンポーネントでラップ可能&quot;
        },
        {
            comparison_items: &quot;ソート&quot;,
            vue_good_table_next: &quot;〇&quot;,
            vue_tables2: &quot;〇&quot;,
            vuetable_2: &quot;〇&quot;,
            grid_js: &quot;〇&quot;
        },
        {
            comparison_items: &quot;ページネーション&quot;,
            vue_good_table_next: &quot;〇&quot;,
            vue_tables2: &quot;〇&quot;,
            vuetable_2: &quot;〇&quot;,
            grid_js: &quot;〇&quot;
        },
        {
            comparison_items: &quot;グループ表示&quot;,
            vue_good_table_next: &quot;〇&quot;,
            vue_tables2: &quot;&lt;span style=&#39;font-size: 1.2em;&#39;&gt;◎&lt;/span&gt;&lt;br&gt;指定の要素で自動的にグループ化&quot;,
            vuetable_2: &quot;？&quot;,
            grid_js: &quot;&lt;span style=&#39;font-size: 1.8em;&#39;&gt;×&lt;/span&gt;&quot;
        },
        {
            comparison_items: &quot;ヘッダー/セルの&lt;br&gt;HTML対応&quot;,
            vue_good_table_next: &quot;〇&quot;,
            vue_tables2: &quot;〇&quot;,
            vuetable_2: &quot;〇&quot;,
            grid_js: &quot;〇&quot;
        },
        {
            comparison_items: &quot;テーブル構成の&lt;br&gt;カスタマイズ&quot;,
            vue_good_table_next: &quot;〇&lt;br&gt;ある程度可能&quot;,
            vue_tables2: &quot;&lt;span style=&#39;font-size: 1.2em;&#39;&gt;◎&lt;/span&gt;&lt;br&gt;カスタムテンプレートで自由度大&quot;,
            vuetable_2: &quot;？&quot;,
            grid_js: &quot;&lt;span style=&#39;font-size: 1.8em;&#39;&gt;×&lt;/span&gt;&quot;
        },
    ];
});
&lt;/script&gt;

&lt;template&gt;
    &lt;VueGoodTable v-bind:columns=&quot;table_columns&quot; v-bind:rows=&quot;table_rows&quot; v-bind:search-options=&quot;search_options&quot;
        v-bind:sort-options=&quot;sort_options&quot; v-bind:pagination-options=&quot;pagination_options&quot;&gt;
        &lt;template #table-column=&quot;props&quot;&gt;
            &lt;span v-if=&quot;props.column.label == &#39;vue-tables2&#39;&quot;&gt;
                {{ props.column.label }}&lt;br&gt;（v-tables3）
            &lt;/span&gt;
            &lt;span v-else&gt;
                {{ props.column.label }}
            &lt;/span&gt;
        &lt;/template&gt;
    &lt;/VueGoodTable&gt;
&lt;/template&gt;

&lt;style&gt;
@import &quot;https://cdn.jsdelivr.net/npm/vue-good-table-next@0.1.0/dist/vue-good-table-next.css&quot;;

table.vgt-table th,
table.vgt-table td {
    vertical-align: middle !important;
}

th.vgt-comparison-items {
    min-width: 10em !important;
}

th.vgt-vue-good-table-next,
th.vgt-vue-tables2,
th.vgt-vuetable-2,
th.vgt-grid-js {
    min-width: 15em !important;
}

td.vgt-vue-good-table-next,
td.vgt-vue-tables2,
td.vgt-vuetable-2,
td.vgt-grid-js {
    font-size: 0.8em;
}
&lt;/style&gt;</code></pre></div>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap javascript"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>////////////////////////////////////////////////////////////////////////////////
// vue-good-table-next モジュール
////////////////////////////////////////////////////////////////////////////////
import { VueGoodTable } from &quot;https://cdn.jsdelivr.net/npm/vue-good-table-next@0.1.0/dist/vue-good-table.cjs.min.js&quot;;
</code></pre></div>



<p>"vue-good-table-next"モジュールをCDNサイト「<a href="https://cdn.jsdelivr.net/npm/vue@next/dist/">https://cdn.jsdelivr.net<span class="fa fa-external-link external-icon anchor-icon"></span></a>」からインポートします。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap html"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;template&gt;
    &lt;VueGoodTable v-bind:columns=&quot;table_columns&quot; v-bind:rows=&quot;table_rows&quot; v-bind:search-options=&quot;search_options&quot;
        v-bind:sort-options=&quot;sort_options&quot; v-bind:pagination-options=&quot;pagination_options&quot;&gt;
        &lt;template #table-column=&quot;props&quot;&gt;
            &lt;span v-if=&quot;props.column.label == &#39;vue-tables2&#39;&quot;&gt;
                {{ props.column.label }}&lt;br&gt;（v-tables3）
            &lt;/span&gt;
            &lt;span v-else&gt;
                {{ props.column.label }}
            &lt;/span&gt;
        &lt;/template&gt;
    &lt;/VueGoodTable&gt;
&lt;/template&gt;</code></pre></div>



<p>インポートした"VueGoodTable"を&lt;template&gt;タグで配置します。</p>



<p>基本は、作成したSFCのローカル変数を"VueGoodTable"のプロパティーにバインドしているだけですが、</p>



<div class="hcb_wrap html"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>        &lt;template #table-column=&quot;props&quot;&gt;
            …
        &lt;/template&gt;
</code></pre></div>



<p>の部分については、「vue-good-table-next」の公式ドキュメントの「<a rel="noopener noreferrer" href="https://borisflesch.github.io/vue-good-table-next/guide/advanced/#custom-column-headers" target="_blank">Custom column headers<span class="fa fa-external-link external-icon anchor-icon"></span></a>」を参照してください。</p>



<p>また、テーブルのコンテンツ（"table_rows"）は、あえて"Vue.onMounted();"の中で設定しました。<br>実際の用途では、"table_rows"を動的に変更すると、テーブルのコンテンツがリアクティブに再表示されます。</p>



<h2 class="wp-block-heading"><span id="toc6">まとめ</span></h2>



<p>「vue-good-table-next」を使うと、WordPressの投稿に多機能なテーブルを手軽に実装できます。<br>しかも、Vueを使っているので、テーブルのコンテンツも簡単に更新/再表示ができます。</p>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>


]]></content:encoded>
					
					<wfw:commentRss>https://vitorec.co.jp/choi-plus-sozai/wordpress%e3%81%ae%e6%8a%95%e7%a8%bf%e3%81%ab%e3%82%bd%e3%83%bc%e3%83%88%e3%82%84%e3%83%9a%e3%83%bc%e3%82%b8%e3%83%8d%e3%83%bc%e3%82%b7%e3%83%a7%e3%83%b3%e3%81%ae%e6%a9%9f%e8%83%bd%e3%82%92%e6%8c%81/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>WordPressの投稿にVue3のSFCを読み込んでChart.jsのチャートを表示する</title>
		<link>https://vitorec.co.jp/choi-plus-sozai/wordpress%e3%81%ae%e6%8a%95%e7%a8%bf%e3%81%abvue3%e3%81%aesfc%e3%82%92%e8%aa%ad%e3%81%bf%e8%be%bc%e3%82%93%e3%81%a7chart-js%e3%81%ae%e3%83%81%e3%83%a3%e3%83%bc%e3%83%88%e3%82%92%e8%a1%a8%e7%a4%ba/</link>
					<comments>https://vitorec.co.jp/choi-plus-sozai/wordpress%e3%81%ae%e6%8a%95%e7%a8%bf%e3%81%abvue3%e3%81%aesfc%e3%82%92%e8%aa%ad%e3%81%bf%e8%be%bc%e3%82%93%e3%81%a7chart-js%e3%81%ae%e3%83%81%e3%83%a3%e3%83%bc%e3%83%88%e3%82%92%e8%a1%a8%e7%a4%ba/#respond</comments>
		
		<dc:creator><![CDATA[管理者]]></dc:creator>
		<pubDate>Thu, 21 Apr 2022 12:38:47 +0000</pubDate>
				<category><![CDATA[Vue3]]></category>
		<category><![CDATA[ブログサイトの立ち上げ方]]></category>
		<guid isPermaLink="false">https://vitorec.co.jp/choi-plus-sozai/?p=10675</guid>

					<description><![CDATA[目次 環境Chart.jsとは？棒グラフを表示するコードの解説"bar_chart.vue"の中身ユーザーインターフェースで棒グラフを操作する"bar_chart_with_ui.vue"の中身まとめ 環境 このページで [&#8230;]]]></description>
										<content:encoded><![CDATA[



  <div id="toc" class="toc tnt-number-detail toc-center tnt-number_detail border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-8" checked><label class="toc-title" for="toc-checkbox-8">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">環境</a></li><li><a href="#toc2" tabindex="0">Chart.jsとは？</a></li><li><a href="#toc3" tabindex="0">棒グラフを表示する</a><ol><li><a href="#toc4" tabindex="0">コードの解説</a></li><li><a href="#toc5" tabindex="0">"bar_chart.vue"の中身</a></li></ol></li><li><a href="#toc6" tabindex="0">ユーザーインターフェースで棒グラフを操作する</a><ol><li><a href="#toc7" tabindex="0">"bar_chart_with_ui.vue"の中身</a></li></ol></li><li><a href="#toc8" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">環境</span></h2>



<p>このページで使用しているフレームワークやライブラリのバージョンは、以下のとおりです。</p>



<figure class="wp-block-table"><table><tbody><tr><td>vue.js</td><td>3.2.31</td></tr><tr><td>vue3-sfc-loader</td><td>0.8.4</td></tr><tr><td>chart.js</td><td>3.6.0</td></tr></tbody></table></figure>



<div class="wp-block-cocoon-blocks-icon-box common-icon-box block-box alert-box">
<p>この記事を書いた後、「<a rel="noopener noreferrer" href="https://vue-chartjs.org/" target="_blank">vue-chartjs<span class="fa fa-external-link external-icon anchor-icon"></span></a>」のバージョン5がリリースされました。<br>「vue-chartjs」バージョン5では、最新の「<a rel="noopener noreferrer" href="https://www.chartjs.org/" target="_blank">Chart.js<span class="fa fa-external-link external-icon anchor-icon"></span></a>」バージョン4をサポートしています。<br>「Chart.js」バージョン4では、チャートのDataやOptionsが変更された場合、再描画するようになりました。なので、この記事で紹介した「Chart.js」を直接ラップする方法より、「vue-chartjs」バージョン5を利用した方が簡単で便利です。</p>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-official">

<a rel="noopener noreferrer" href="https://vue-chartjs.org/" title="&#128200; vue-chartjs" class="blogcard-wrap external-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard external-blogcard eb-left cf"><div class="blogcard-label external-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail external-blogcard-thumbnail"><img loading="lazy" decoding="async" src="https://s.wordpress.com/mshots/v1/https%3A%2F%2Fvue-chartjs.org%2F?w=160&#038;h=90" alt="" class="blogcard-thumb-image external-blogcard-thumb-image" width="160" height="90" /></figure><div class="blogcard-content external-blogcard-content"><div class="blogcard-title external-blogcard-title">&#128200; vue-chartjs</div><div class="blogcard-snippet external-blogcard-snippet">⚡ Easy and beautiful charts with Chart.js and Vue.js</div></div><div class="blogcard-footer external-blogcard-footer cf"><div class="blogcard-site external-blogcard-site"><div class="blogcard-favicon external-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://vue-chartjs.org/" alt="" class="blogcard-favicon-image external-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain external-blogcard-domain">vue-chartjs.org</div></div></div></div></a>
</div>
</div>



<h2 class="wp-block-heading"><span id="toc2">Chart.jsとは？</span></h2>



<p>「<a rel="noopener noreferrer" href="https://www.chartjs.org/" target="_blank">Chart.js<span class="fa fa-external-link external-icon anchor-icon"></span></a>」は、チャート（グラフ）を表示するJavaScriptライブラリです。<br />機能の豊富さと表示の美しさで、この「Chart.js」を越えるJavaScriptライブラリはないと思います。<br />MITライセンスで、無償で利用できます。</p>
<p>2021年の4月に、メジャーバージョンが「2.x」から「3.x」に変わり、<a rel="noopener noreferrer" href="https://www.chartjs.org/docs/latest/getting-started/v3-migration.html" target="_blank">仕様も大きく変わっています<span class="fa fa-external-link external-icon anchor-icon"></span></a>。<br />なので、今から「Chart.js」を利用する方は、バージョン「3.x」を使うことをお勧めします。</p>
<p>Vue3で「Chart.js」を使えるようにしたコンポーネント「<a rel="noopener noreferrer" href="https://vue-chartjs.org/" target="_blank">vue-chartjs<span class="fa fa-external-link external-icon anchor-icon"></span></a>」もあります。<br />「vue-chartjs」のバージョン「4.x」から、「Chart.js」のバージョン「3.x」に対応しているので、Vueの環境で簡単に「Chart.js」を使いたい場合は、「vue-chartjs」を利用すると良いでしょう。</p>
<p>ただし、「vue-chartjs」のバージョン「4.0.5」では、ドキュメントに以下の記載があり、チャートのOptionsを変更しても、チャートが再描画されません。</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong><span class="fz-22px">Options</span></strong><br>The options object is not currently implemented reactively. Therefore, if you dynamically change the chart options, they will not be recognized by the update data handler.</p>
</blockquote>



<p>なので、この記事では「vue-chartjs」を使わず、「Chart.js」を直接ラップしたSFCを作成し、このコンポーネントでチャートを表示します。</p>



<p>WordPressの投稿にVueのSFCを読み込む方法については、以下の記事で紹介しています。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-related">

<a href="https://vitorec.co.jp/choi-plus-sozai/%e3%83%96%e3%83%a9%e3%82%a6%e3%82%b6%e7%92%b0%e5%a2%83%e3%81%a7vue3%e3%81%ae%e5%8d%98%e4%b8%80%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%82%b3%e3%83%b3%e3%83%9d%e3%83%bc%e3%83%8d%e3%83%b3%e3%83%88/" title="WordPressのサイトでVue3の単一ファイルコンポーネントを使う" class="blogcard-wrap external-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard external-blogcard eb-left cf"><div class="blogcard-label external-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail external-blogcard-thumbnail"><img loading="lazy" decoding="async" src="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/cocoon-resources/blog-card-cache/11d1f1030333d800c479e7742dd73450.png" alt="" class="blogcard-thumb-image external-blogcard-thumb-image" width="160" height="90" /></figure><div class="blogcard-content external-blogcard-content"><div class="blogcard-title external-blogcard-title">WordPressのサイトでVue3の単一ファイルコンポーネントを使う</div><div class="blogcard-snippet external-blogcard-snippet">「vue3-sfc-loader」を使うと、「Node.js」が無いブラウザ環境でもVue3の単一ファイルコンポーネントを使うことができます。</div></div><div class="blogcard-footer external-blogcard-footer cf"><div class="blogcard-site external-blogcard-site"><div class="blogcard-favicon external-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://vitorec.co.jp/choi-plus-sozai/wordpress%e3%81%ae%e3%82%b5%e3%82%a4%e3%83%88%e3%81%a7vue3%e3%81%ae%e5%8d%98%e4%b8%80%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%82%b3%e3%83%b3%e3%83%9d%e3%83%bc%e3%83%8d%e3%83%b3%e3%83%88%e3%82%92/" alt="" class="blogcard-favicon-image external-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain external-blogcard-domain">vitorec.co.jp</div></div></div></div></a>
</div>



<h2 class="wp-block-heading"><span id="toc3">棒グラフを表示する</span></h2>



<p>まずは、簡単な棒グラフを表示してみましょう。<br>このチャートは、「Chart.js」の<a rel="noopener noreferrer" href="https://www.chartjs.org/docs/latest/" target="_blank">ドキュメント<span class="fa fa-external-link external-icon anchor-icon"></span></a>の最初の例に出てくる棒グラフです。</p>



<script src="https://cdn.jsdelivr.net/npm/vue@3.2.31/dist/vue.global.js"></script>

<div id="app"></div>

<script type="module">
    ////////////////////////////////////////////////////////////////////////////////
    // vue3-sfc-loader モジュール
    ////////////////////////////////////////////////////////////////////////////////
    import { loadModule } from "https://cdn.jsdelivr.net/npm/vue3-sfc-loader@0.8.4/dist/vue3-sfc-loader.esm.js";

    ////////////////////////////////////////////////////////////////////////////////
    // vue3-sfc-loader オプション
    // SFCファイルから外部のモジュールをimportできるオプション
    // 参考：https://github.com/FranckFreiburger/vue3-sfc-loader/issues/14#issuecomment-908849863
    ////////////////////////////////////////////////////////////////////////////////
    const vue3_sfc_loader_options = {
        moduleCache: { vue: Vue },
        getFile(url) {
            url = /.*?\.js|.mjs|.css|.less|.vue$/.test(url)
                ? url
                : `${url}.vue`;
            const type = /.*?\.js|.mjs$/.test(url)
                ? ".mjs"
                : /.*?\.vue$/.test(url)
                ? ".vue"
                : /.*?\.css$/.test(url)
                ? ".css"
                : ".vue";
            const getContentData = (asBinary) =>
                fetch(url).then((res) =>
                    !res.ok
                        ? Promise.reject(url)
                        : asBinary
                        ? res.arrayBuffer()
                        : res.text()
                );
            return { getContentData: getContentData, type: type };
        },
        addStyle(textContent) {
            let styleElement = document.createElement("style");
            document.head.insertBefore(
                Object.assign(styleElement, { textContent }),
                document.head.getElementsByTagName("style")[0] || null
            );
        },
        handleModule(type, getContentData, path, options) {
            switch (type) {
                case ".css":
                    return options.addStyle(getContentData(false));
                case ".less":
                    console.error(".......");
            }
        },
        log(type, ...args) {
            console.log(type, ...args);
        },
    };

    ////////////////////////////////////////////////////////////////////////////////
    // Vue.js アプリケーションインスタンス
    ////////////////////////////////////////////////////////////////////////////////
    const app = Vue.createApp({
        components: {
            "bar-chart": Vue.defineAsyncComponent(() =>
                loadModule(
                    "../wp-content/themes/cocoon-child-master/vue-components/bar_chart.vue",
                    vue3_sfc_loader_options
                )
            ),
        },
        template: `<bar-chart />`,
    });
    app.mount("#app");
</script>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<p>チャートが表示されている部分には、WordPressのブロックエディタで以下の「カスタム HTML」ブロックを配置しています。</p>



<div class="hcb_wrap html"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue@3.2.31/dist/vue.global.js&quot;&gt;&lt;/script&gt;

&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;

&lt;script type=&quot;module&quot;&gt;
    ////////////////////////////////////////////////////////////////////////////////
    // vue3-sfc-loader モジュール
    ////////////////////////////////////////////////////////////////////////////////
    import { loadModule } from &quot;https://cdn.jsdelivr.net/npm/vue3-sfc-loader@0.8.4/dist/vue3-sfc-loader.esm.js&quot;;

    ////////////////////////////////////////////////////////////////////////////////
    // vue3-sfc-loader オプション
    // SFCファイルから外部のモジュールをimportできるオプション
    // 参考：https://github.com/FranckFreiburger/vue3-sfc-loader/issues/14#issuecomment-908849863
    ////////////////////////////////////////////////////////////////////////////////
    const vue3_sfc_loader_options = {
        moduleCache: { vue: Vue },
        getFile(url) {
            url = /.*?\.js|.mjs|.css|.less|.vue$/.test(url)
                ? url
                : `${url}.vue`;
            const type = /.*?\.js|.mjs$/.test(url)
                ? &quot;.mjs&quot;
                : /.*?\.vue$/.test(url)
                ? &quot;.vue&quot;
                : /.*?\.css$/.test(url)
                ? &quot;.css&quot;
                : &quot;.vue&quot;;
            const getContentData = (asBinary) =&gt;
                fetch(url).then((res) =&gt;
                    !res.ok
                        ? Promise.reject(url)
                        : asBinary
                        ? res.arrayBuffer()
                        : res.text()
                );
            return { getContentData: getContentData, type: type };
        },
        addStyle(textContent) {
            let styleElement = document.createElement(&quot;style&quot;);
            document.head.insertBefore(
                Object.assign(styleElement, { textContent }),
                document.head.getElementsByTagName(&quot;style&quot;)[0] || null
            );
        },
        handleModule(type, getContentData, path, options) {
            switch (type) {
                case &quot;.css&quot;:
                    return options.addStyle(getContentData(false));
                case &quot;.less&quot;:
                    console.error(&quot;.......&quot;);
            }
        },
        log(type, ...args) {
            console.log(type, ...args);
        },
    };

    ////////////////////////////////////////////////////////////////////////////////
    // Vue.js アプリケーションインスタンス
    ////////////////////////////////////////////////////////////////////////////////
    const app = Vue.createApp({
        components: {
            &quot;bar-chart&quot;: Vue.defineAsyncComponent(() =&gt;
                loadModule(
                    &quot;../wp-content/themes/cocoon-child-master/vue-components/bar_chart.vue&quot;,
                    vue3_sfc_loader_options
                )
            ),
        },
        template: `&lt;bar-chart /&gt;`,
    });
    app.mount(&quot;#app&quot;);
&lt;/script&gt;</code></pre></div>



<h3 class="wp-block-heading"><span id="toc4">コードの解説</span></h3>



<p>前回の紹介記事「<a href="https://vitorec.co.jp/choi-plus-sozai/%e3%83%96%e3%83%a9%e3%82%a6%e3%82%b6%e7%92%b0%e5%a2%83%e3%81%a7vue3%e3%81%ae%e5%8d%98%e4%b8%80%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%82%b3%e3%83%b3%e3%83%9d%e3%83%bc%e3%83%8d%e3%83%b3%e3%83%88/" target="_blank">ブラウザ環境でVue3の単一ファイルコンポーネントを使う</a>」からの差分を中心に解説します。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap javascript"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>    ////////////////////////////////////////////////////////////////////////////////
    // Vue.js アプリケーションインスタンス
    ////////////////////////////////////////////////////////////////////////////////
    const app = Vue.createApp({
        components: {
            &quot;bar-chart&quot;: Vue.defineAsyncComponent(() =&gt;
                loadModule(
                    &quot;../wp-content/themes/cocoon-child-master/vue-components/bar_chart.vue&quot;,
                    vue3_sfc_loader_options
                )
            ),
        },
        template: `&lt;bar-chart /&gt;`,
    });
    app.mount(&quot;#app&quot;);
</code></pre></div>



<p>アプリケーションインスタンスの作成とマウントの方法は、前回の「<a href="https://vitorec.co.jp/choi-plus-sozai/%e3%83%96%e3%83%a9%e3%82%a6%e3%82%b6%e7%92%b0%e5%a2%83%e3%81%a7vue3%e3%81%ae%e5%8d%98%e4%b8%80%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%82%b3%e3%83%b3%e3%83%9d%e3%83%bc%e3%83%8d%e3%83%b3%e3%83%88/" target="_blank">ブラウザ環境でVue3の単一ファイルコンポーネントを使う</a>」と同じ流れです。<br>違うのは、"bar_chart.vue"というSFCを"bar-chart"という名前のコンポーネントとして読み込んで、`&lt;bar-chart /&gt;`で表示している点です。</p>



<h3 class="wp-block-heading"><span id="toc5">"bar_chart.vue"の中身</span></h3>



<p>"bar_chart.vue"の全体です。</p>



<div class="hcb_wrap html"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;script setup&gt;
////////////////////////////////////////////////////////////////////////////////
// Chart.js モジュール
////////////////////////////////////////////////////////////////////////////////
// Chart.jsモジュールのimportとregisterを行う
import { Chart, registerables } from &quot;../chart.js-3.6.0/dist/chart.esm.js&quot;;
Chart.register(...registerables);

////////////////////////////////////////////////////////////////////////////////
// data
////////////////////////////////////////////////////////////////////////////////
let chart = {}; // チャートオブジェクト
const chart_height = 400; // チャートの高さ
let chart_options = { // チャートのオプション
    scales: {
        y: {
            beginAtZero: true
        }
    },
};
let chart_data = { // チャートのデータ
    labels: [&quot;Red&quot;, &quot;Blue&quot;, &quot;Yellow&quot;, &quot;Green&quot;, &quot;Purple&quot;, &quot;Orange&quot;],
    datasets: [{
        label: &quot;# of Votes&quot;,
        data: [12, 19, 3, 5, 2, 3],
        backgroundColor: [
            &quot;rgba(255, 99, 132, 0.2)&quot;,
            &quot;rgba(54, 162, 235, 0.2)&quot;,
            &quot;rgba(255, 206, 86, 0.2)&quot;,
            &quot;rgba(75, 192, 192, 0.2)&quot;,
            &quot;rgba(153, 102, 255, 0.2)&quot;,
            &quot;rgba(255, 159, 64, 0.2)&quot;
        ],
        borderColor: [
            &quot;rgba(255, 99, 132, 1)&quot;,
            &quot;rgba(54, 162, 235, 1)&quot;,
            &quot;rgba(255, 206, 86, 1)&quot;,
            &quot;rgba(75, 192, 192, 1)&quot;,
            &quot;rgba(153, 102, 255, 1)&quot;,
            &quot;rgba(255, 159, 64, 1)&quot;
        ],
        borderWidth: 1
    }]
};

////////////////////////////////////////////////////////////////////////////////
// onMountedライフサイクルフック
////////////////////////////////////////////////////////////////////////////////
Vue.onMounted(() =&gt; {
    renderChart();
});

////////////////////////////////////////////////////////////////////////////////
// チャートを描画する
////////////////////////////////////////////////////////////////////////////////
const renderChart = () =&gt; {
    const ctx = document.getElementById(&quot;chart&quot;).getContext(&quot;2d&quot;);
    chart = new Chart(ctx, {
        type: &quot;bar&quot;,
        data: chart_data,
        options: chart_options,
    });
};
&lt;/script&gt;

&lt;template&gt;
    &lt;div&gt;
        &lt;canvas id=&quot;chart&quot; width=&quot;100%&quot; v-bind:height=&quot;chart_height&quot;&gt;&lt;/canvas&gt;
    &lt;/div&gt;
&lt;/template&gt;

&lt;style&gt;
&lt;/style&gt;</code></pre></div>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<p>"bar_chart.vue"のセットアップは、</p>



<div class="hcb_wrap html"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;script&gt;
export default defineComponent({
    setup() {
        …
    },
});
&lt;/script&gt;</code></pre></div>



<p>を使わずに、</p>



<div class="hcb_wrap html"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;script setup&gt;
    …
&lt;/script&gt;</code></pre></div>



<p>の中でやっています。</p>



<p>&lt;script setup&gt;については、Vue3の公式ドキュメント「<a rel="noopener noreferrer" href="https://v3.ja.vuejs.org/api/sfc-script-setup.html" target="_blank">SFC&lt;script setup&gt;<span class="fa fa-external-link external-icon anchor-icon"></span></a>」を参照してください。<br>&lt;script setup&gt;の利便性については、以下の記事が参考になります。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-reference">

<a rel="noopener noreferrer" href="https://zenn.dev/azukiazusa/articles/676d88675e4e74" title="【Vue.js 3.2】`` 構文がすごくすごい" class="blogcard-wrap external-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard external-blogcard eb-left cf"><div class="blogcard-label external-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail external-blogcard-thumbnail"><img loading="lazy" decoding="async" src="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/cocoon-resources/blog-card-cache/d508310b83eec34aeaa616c715f5bd29.png" alt="" class="blogcard-thumb-image external-blogcard-thumb-image" width="160" height="90" /></figure><div class="blogcard-content external-blogcard-content"><div class="blogcard-title external-blogcard-title">【Vue.js 3.2】`` 構文がすごくすごい</div><div class="blogcard-snippet external-blogcard-snippet"></div></div><div class="blogcard-footer external-blogcard-footer cf"><div class="blogcard-site external-blogcard-site"><div class="blogcard-favicon external-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://zenn.dev/azukiazusa/articles/676d88675e4e74" alt="" class="blogcard-favicon-image external-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain external-blogcard-domain">zenn.dev</div></div></div></div></a>
</div>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap javascript"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>////////////////////////////////////////////////////////////////////////////////
// Chart.js モジュール
////////////////////////////////////////////////////////////////////////////////
// Chart.jsモジュールのimportとregisterを行う
import { Chart, registerables } from &quot;../chart.js-3.6.0/dist/chart.esm.js&quot;;
Chart.register(...registerables);</code></pre></div>



<p>「Chart.js」ライブラリ一式をCDNサイト「<a rel="noopener noreferrer" href="https://www.jsdelivr.com/package/npm/chart.js" target="_blank">https://www.jsdelivr.com/package/npm/chart.js<span class="fa fa-external-link external-icon anchor-icon"></span></a>」からダウンロードして、適当なフォルダに保存します。<br>「ちょいプラ素材」のブログは、WordPressのテーマに「<a rel="noopener noreferrer" href="https://wp-cocoon.com/" target="_blank">Cocoon<span class="fa fa-external-link external-icon anchor-icon"></span></a>」を使っています。<br>今回は、「<a rel="noopener noreferrer" href="https://wp-cocoon.com/" target="_blank">Cocoon<span class="fa fa-external-link external-icon anchor-icon"></span></a>」の子テーマ「<a rel="noopener noreferrer" href="https://wp-cocoon.com/downloads/#toc3" target="_blank">cocoon-child-master<span class="fa fa-external-link external-icon anchor-icon"></span></a>」の下に"chart.js-3.6.0"というフォルダを作って保存しました。</p>



<p>SFC"bar_chart.vue"が保存されているフォルダからの相対パス"../chart.js-3.6.0/dist/chart.esm.js"で「Chart.js」のESモジュール"chart.esm.js"をインポートします。</p>



<p>「Chart.js」モジュールをインポートした後は、実際に利用するモジュールの登録（register）が必要です。1つ1つのモジュールを登録するのは面倒なので、"Chart.register(...registerables);"でまとめて登録しています。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap javascript"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>////////////////////////////////////////////////////////////////////////////////
// data
////////////////////////////////////////////////////////////////////////////////
let chart = {}; // チャートオブジェクト
const chart_height = 400; // チャートの高さ
let chart_options = { // チャートのオプション
    …
};
let chart_data = { // チャートのデータ
    …
};</code></pre></div>



<p>このSFCだけで使うデータを宣言しています。<br>それぞれのデータの意味は、コメントを見てください。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap javascript"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>////////////////////////////////////////////////////////////////////////////////
// onMountedライフサイクルフック
////////////////////////////////////////////////////////////////////////////////
Vue.onMounted(() =&gt; {
    renderChart();
});</code></pre></div>



<p>このSFCがマウントされたときに呼ばれる、ライフサイクルフックです。<br>SFCがマウントされたら、この後に説明する"renderChart();"を実行します。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap javascript"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>////////////////////////////////////////////////////////////////////////////////
// チャートを描画する
////////////////////////////////////////////////////////////////////////////////
const renderChart = () =&gt; {
    const ctx = document.getElementById(&quot;chart&quot;).getContext(&quot;2d&quot;);
    chart = new Chart(ctx, {
        type: &quot;bar&quot;,
        data: chart_data,
        options: chart_options,
    });
};</code></pre></div>



<p>チャートを描画する処理です。<br>この後の&lt;template&gt;タグで配置される&lt;canvas id="chart"&gt;要素に「Chart.js」の"bar"モジュール（棒グラフモジュール）を紐づけます。<br><br>また、"chart = new Chart();"で作成した「Chart.js」のモジュール（JavaScriptのオブジェクト）を変数"chart"に保存しておきます。<br>こうすることで、「Chart.js」のメソッド（関数）を使って、作成した"bar"モジュールを操作することができます。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap html"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;template&gt;
    &lt;div&gt;
        &lt;canvas id=&quot;chart&quot; width=&quot;100%&quot; v-bind:height=&quot;chart_height&quot;&gt;&lt;/canvas&gt;
    &lt;/div&gt;
&lt;/template&gt;</code></pre></div>



<p>&lt;template&gt;タグで&lt;canvas id="chart"&gt;要素を配置します。</p>



<h2 class="wp-block-heading"><span id="toc6">ユーザーインターフェースで棒グラフを操作する</span></h2>



<p>次に、先ほどの棒グラフを表示するSFCにユーザーインターフェースを追加して、チャートを操作してみましょう。<br>ユーザーインターフェースとデータの連携は、Vueが得意とするところです。</p>



<div id="app2"></div>

<script type="module">
    ////////////////////////////////////////////////////////////////////////////////
    // vue3-sfc-loader モジュール
    ////////////////////////////////////////////////////////////////////////////////
    import { loadModule } from "https://cdn.jsdelivr.net/npm/vue3-sfc-loader@0.8.4/dist/vue3-sfc-loader.esm.js";

    ////////////////////////////////////////////////////////////////////////////////
    // vue3-sfc-loader オプション
    // SFCファイルから外部のモジュールをimportできるオプション
    // 参考：https://github.com/FranckFreiburger/vue3-sfc-loader/issues/14#issuecomment-908849863
    ////////////////////////////////////////////////////////////////////////////////
    const vue3_sfc_loader_options = {
        moduleCache: { vue: Vue },
        getFile(url) {
            url = /.*?\.js|.mjs|.css|.less|.vue$/.test(url)
                ? url
                : `${url}.vue`;
            const type = /.*?\.js|.mjs$/.test(url)
                ? ".mjs"
                : /.*?\.vue$/.test(url)
                ? ".vue"
                : /.*?\.css$/.test(url)
                ? ".css"
                : ".vue";
            const getContentData = (asBinary) =>
                fetch(url).then((res) =>
                    !res.ok
                        ? Promise.reject(url)
                        : asBinary
                        ? res.arrayBuffer()
                        : res.text()
                );
            return { getContentData: getContentData, type: type };
        },
        addStyle(textContent) {
            let styleElement = document.createElement("style");
            document.head.insertBefore(
                Object.assign(styleElement, { textContent }),
                document.head.getElementsByTagName("style")[0] || null
            );
        },
        handleModule(type, getContentData, path, options) {
            switch (type) {
                case ".css":
                    return options.addStyle(getContentData(false));
                case ".less":
                    console.error(".......");
            }
        },
        log(type, ...args) {
            console.log(type, ...args);
        },
    };

    ////////////////////////////////////////////////////////////////////////////////
    // Vue.js アプリケーションインスタンス
    ////////////////////////////////////////////////////////////////////////////////
    const app = Vue.createApp({
        components: {
            "bar-chart": Vue.defineAsyncComponent(() =>
                loadModule(
                    "../wp-content/themes/cocoon-child-master/vue-components/bar_chart_with_ui.vue",
                    vue3_sfc_loader_options
                )
            ),
        },
        template: `<bar-chart />`,
    });
    app.mount("#app2");
</script>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<p>［データを変更］ボタンを押すと、データが0～50の範囲の整数にランダムに変化します。<br>［縦軸の最大値］スライダーを動かすと、チャートの縦軸の最大値を変更できます。</p>



<h3 class="wp-block-heading"><span id="toc7">"bar_chart_with_ui.vue"の中身</span></h3>



<p>新しく作成したSFC"bar_chart_with_ui.vue"の全体です。</p>



<div class="hcb_wrap html"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;script setup&gt;
////////////////////////////////////////////////////////////////////////////////
// Chart.js モジュール
////////////////////////////////////////////////////////////////////////////////
// Chart.jsモジュールのimportとregisterを行う
import { Chart, registerables } from &quot;../chart.js-3.6.0/dist/chart.esm.js&quot;;
Chart.register(...registerables);

////////////////////////////////////////////////////////////////////////////////
// data
////////////////////////////////////////////////////////////////////////////////
let chart = {}; // チャートオブジェクト
const chart_height = 400; // チャートの高さ
let y_max = Vue.ref(50); // 縦軸の最大値
let chart_options = { // チャートのオプション
    scales: {
        y: {
            beginAtZero: true,
            min: 0,
            max: y_max.value,
        }
    },
};
let chart_data = { // チャートのデータ
    labels: [&quot;Red&quot;, &quot;Blue&quot;, &quot;Yellow&quot;, &quot;Green&quot;, &quot;Purple&quot;, &quot;Orange&quot;],
    datasets: [{
        label: &quot;# of Votes&quot;,
        data: [12, 19, 3, 5, 2, 3],
        backgroundColor: [
            &quot;rgba(255, 99, 132, 0.2)&quot;,
            &quot;rgba(54, 162, 235, 0.2)&quot;,
            &quot;rgba(255, 206, 86, 0.2)&quot;,
            &quot;rgba(75, 192, 192, 0.2)&quot;,
            &quot;rgba(153, 102, 255, 0.2)&quot;,
            &quot;rgba(255, 159, 64, 0.2)&quot;
        ],
        borderColor: [
            &quot;rgba(255, 99, 132, 1)&quot;,
            &quot;rgba(54, 162, 235, 1)&quot;,
            &quot;rgba(255, 206, 86, 1)&quot;,
            &quot;rgba(75, 192, 192, 1)&quot;,
            &quot;rgba(153, 102, 255, 1)&quot;,
            &quot;rgba(255, 159, 64, 1)&quot;
        ],
        borderWidth: 1
    }]
};

////////////////////////////////////////////////////////////////////////////////
// onMountedライフサイクルフック
////////////////////////////////////////////////////////////////////////////////
Vue.onMounted(() =&gt; {
    renderChart();
});

////////////////////////////////////////////////////////////////////////////////
// チャートを描画する
////////////////////////////////////////////////////////////////////////////////
const renderChart = () =&gt; {
    const ctx = document.getElementById(&quot;chart2&quot;).getContext(&quot;2d&quot;);
    chart = new Chart(ctx, {
        type: &quot;bar&quot;,
        data: chart_data,
        options: chart_options,
    });
};

////////////////////////////////////////////////////////////////////////////////
// チャートのデータを変更する
////////////////////////////////////////////////////////////////////////////////
const onChangeData = () =&gt; {
    chart_data.datasets[0].data = [
        Math.floor(Math.random() * 51),
        Math.floor(Math.random() * 51),
        Math.floor(Math.random() * 51),
        Math.floor(Math.random() * 51),
        Math.floor(Math.random() * 51),
        Math.floor(Math.random() * 51),
    ];
    chart.update(); // チャートを再描画する
};

////////////////////////////////////////////////////////////////////////////////
// 縦軸の最大値を変更する
////////////////////////////////////////////////////////////////////////////////
const onChangeYMax = () =&gt; {
    chart_options.scales.y.max = y_max.value;
    chart.update(); // チャートを再描画する
};
&lt;/script&gt;

&lt;template&gt;
    &lt;div&gt;
        &lt;canvas id=&quot;chart2&quot; width=&quot;100%&quot; v-bind:height=&quot;chart_height&quot;&gt;&lt;/canvas&gt;
        &lt;form class=&quot;chart-ui-form&quot;&gt;
            &lt;input type=&quot;button&quot; class=&quot;data-change-button&quot; v-on:click=&quot;onChangeData&quot; value=&quot;データを変更&quot; /&gt;
            &lt;div class=&quot;chart-range-container&quot;&gt;
                &lt;span style=&quot;margin-right: 0.2em&quot;&gt;縦軸の最大値　10&lt;/span&gt;
                &lt;input type=&quot;range&quot; id=&quot;view-time-start-range&quot; class=&quot;y-max-range&quot; v-model.number=&quot;y_max&quot; min=&quot;10&quot;
                    max=&quot;100&quot; step=&quot;10&quot; v-on:mouseup=&quot;onChangeYMax&quot; v-on:touchend=&quot;onChangeYMax&quot; /&gt;
                &lt;span style=&quot;margin-left: 0.2em&quot;&gt;100&lt;/span&gt;
            &lt;/div&gt;
        &lt;/form&gt;
    &lt;/div&gt;
&lt;/template&gt;

&lt;style&gt;
.chart-ui-form {
    margin: 20px;
}

.chart-range-container {
    margin-left: 10px;
    margin-top: 10px;
}

.data-change-button {
    color: #fff;
    background-color: #3b83d8;
    font-weight: bold;
    border-radius: 4px;
    display: inline-block;
    cursor: pointer;
    line-height: normal;
    padding: 7px 13px;
    text-decoration: none;
    text-align: center;
    font-size: 14px;
    border: 2px solid transparent;
    position: relative;
}

.y-max-range {
    max-width: 40%;
    width: 40%;
}
&lt;/style&gt;</code></pre></div>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<p>SFCの変更点を解説します。</p>



<div class="hcb_wrap javascript"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>let y_max = Vue.ref(50); // 縦軸の最大値
let chart_options = { // チャートのオプション
    scales: {
        y: {
            beginAtZero: true,
            min: 0,
            max: y_max.value,
        }
    },
};</code></pre></div>



<p>チャートのオプションを指定する"chart_options"の"scale.y"オブジェクトに、"min"と"max"を追加しました。<br>"min"、"max"を指定しない場合は、データの値に応じて、「Chart.js」が軸の表示を最適に調整してくれます。</p>



<p>"max"には、新しく追加した変数"y_max"の値を設定します。<br>また、変数"y_max"は、Vueの「<a rel="noopener noreferrer" href="https://v3.ja.vuejs.org/guide/reactivity-fundamentals.html#%E3%83%AA%E3%82%A2%E3%82%AF%E3%83%86%E3%82%A3%E3%83%95%E3%82%99%E3%81%AA%E7%8A%B6%E6%85%8B%E3%81%AE%E5%AE%A3%E8%A8%80" target="_blank">refメソッド<span class="fa fa-external-link external-icon anchor-icon"></span></a>」でリアクティブな変数にしています。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap javascript"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>////////////////////////////////////////////////////////////////////////////////
// チャートのデータを変更する
////////////////////////////////////////////////////////////////////////////////
const onChangeData = () =&gt; {
    chart_data.datasets[0].data = [
        Math.floor(Math.random() * 51),
        Math.floor(Math.random() * 51),
        Math.floor(Math.random() * 51),
        Math.floor(Math.random() * 51),
        Math.floor(Math.random() * 51),
        Math.floor(Math.random() * 51),
    ];
    chart.update(); // チャートを再描画する
};</code></pre></div>



<p>［データを変更］ボタンが押されたときに呼ばれるイベントハンドラーです。<br>チャートのデータが0～50の範囲の整数にランダムに変化します。<br>実際の用途では、チャートに表示したいデータの設定処理を実装します。</p>



<p>その後、"chart.update();"でチャートを再描画します。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap javascript"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>////////////////////////////////////////////////////////////////////////////////
// 縦軸の最大値を変更する
////////////////////////////////////////////////////////////////////////////////
const onChangeYMax = () =&gt; {
    chart_options.scales.y.max = y_max.value;
    chart.update(); // チャートを再描画する
};</code></pre></div>



<p>［縦軸の最大値］スライダーを動かした後、マウスのボタンを離すと呼ばれるイベントハンドラーです。<br>チャートのオプション"chart_options.scales.y.max"の値を変更した後、"chart.update();"でチャートを再描画します。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap html"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;template&gt;
    …
&lt;/template&gt;

&lt;style&gt;
    …
&lt;/style&gt;</code></pre></div>



<p>&lt;template&gt;タグと&lt;style&gt;タグで、SFCの外観（ビュー）を定義します。</p>



<p>以上のように、VueのSFCを使うと、</p>



<ul class="wp-block-list">
<li>ユーザーインターフェースの操作をトリガーにして、</li>



<li>必要なデータやオプションを変更し、</li>



<li>「Chart.js」のupdate()メソッドを呼び出すだけで、</li>
</ul>



<p>チャートの表示を動的に、しかも簡単に操作できます。</p>



<h2 class="wp-block-heading"><span id="toc8">まとめ</span></h2>



<p>「Chart.js」を直接ラップしたSFCを作成し、コンポーネントでチャートを表示する方法を紹介しました。</p>



<p>チャートのデータやオプションを動的に変えることができるので、WordPressのデータベースのデータをビジュアルに表示したり、データが保存されているCSVファイルをアップロードして、CSVファイルのデータをチャートで確認したり、いろいろなシチュエーションで活用できるはずです。</p>



<p>次は、WordPressの投稿に「<a rel="noopener noreferrer" href="https://borisflesch.github.io/vue-good-table-next/" target="_blank">vue-good-table-next<span class="fa fa-external-link external-icon anchor-icon"></span></a>」のテーブルを表示してみましょう。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-related">

<a href="https://vitorec.co.jp/choi-plus-sozai/wordpress%e3%81%ae%e6%8a%95%e7%a8%bf%e3%81%ab%e3%82%bd%e3%83%bc%e3%83%88%e3%82%84%e3%83%9a%e3%83%bc%e3%82%b8%e3%83%8d%e3%83%bc%e3%82%b7%e3%83%a7%e3%83%b3%e3%81%ae%e6%a9%9f%e8%83%bd%e3%82%92%e6%8c%81/" title="WordPressの投稿にソートやページネーションの機能を持ったテーブルを実装する" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/vue-good-table-next-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/vue-good-table-next-160x90.png 160w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/vue-good-table-next-120x68.png 120w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/vue-good-table-next-320x180.png 320w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">WordPressの投稿にソートやページネーションの機能を持ったテーブルを実装する</div><div class="blogcard-snippet internal-blogcard-snippet">VueのSFCを介して「vue-good-table-next」を使うと、WordPressの投稿に多機能なテーブルを手軽に実装できます。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://vitorec.co.jp/choi-plus-sozai" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">vitorec.co.jp</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2024.07.25</div></div></div></div></a>
</div>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>
]]></content:encoded>
					
					<wfw:commentRss>https://vitorec.co.jp/choi-plus-sozai/wordpress%e3%81%ae%e6%8a%95%e7%a8%bf%e3%81%abvue3%e3%81%aesfc%e3%82%92%e8%aa%ad%e3%81%bf%e8%be%bc%e3%82%93%e3%81%a7chart-js%e3%81%ae%e3%83%81%e3%83%a3%e3%83%bc%e3%83%88%e3%82%92%e8%a1%a8%e7%a4%ba/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>WordPressのサイトでVue3の単一ファイルコンポーネントを使う</title>
		<link>https://vitorec.co.jp/choi-plus-sozai/wordpress%e3%81%ae%e3%82%b5%e3%82%a4%e3%83%88%e3%81%a7vue3%e3%81%ae%e5%8d%98%e4%b8%80%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%82%b3%e3%83%b3%e3%83%9d%e3%83%bc%e3%83%8d%e3%83%b3%e3%83%88%e3%82%92/</link>
					<comments>https://vitorec.co.jp/choi-plus-sozai/wordpress%e3%81%ae%e3%82%b5%e3%82%a4%e3%83%88%e3%81%a7vue3%e3%81%ae%e5%8d%98%e4%b8%80%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%82%b3%e3%83%b3%e3%83%9d%e3%83%bc%e3%83%8d%e3%83%b3%e3%83%88%e3%82%92/#respond</comments>
		
		<dc:creator><![CDATA[管理者]]></dc:creator>
		<pubDate>Wed, 20 Apr 2022 09:52:07 +0000</pubDate>
				<category><![CDATA[Vue3]]></category>
		<category><![CDATA[ブログサイトの立ち上げ方]]></category>
		<guid isPermaLink="false">https://vitorec.co.jp/choi-plus-sozai/?p=10600</guid>

					<description><![CDATA[目次 環境Vueのコンポーネントとは？単一ファイルコンポーネントとは？ブラウザ環境で単一ファイルコンポーネントを使うには？「vue3-sfc-loader」の使い方コードの解説"hello_world.vue"の中身まと [&#8230;]]]></description>
										<content:encoded><![CDATA[

  <div id="toc" class="toc tnt-number-detail toc-center tnt-number_detail border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-10" checked><label class="toc-title" for="toc-checkbox-10">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">環境</a></li><li><a href="#toc2" tabindex="0">Vueのコンポーネントとは？</a></li><li><a href="#toc3" tabindex="0">単一ファイルコンポーネントとは？</a></li><li><a href="#toc4" tabindex="0">ブラウザ環境で単一ファイルコンポーネントを使うには？</a></li><li><a href="#toc5" tabindex="0">「vue3-sfc-loader」の使い方</a><ol><li><a href="#toc6" tabindex="0">コードの解説</a></li><li><a href="#toc7" tabindex="0">"hello_world.vue"の中身</a></li></ol></li><li><a href="#toc8" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">環境</span></h2>



<p>このページで使用しているフレームワークやライブラリのバージョンは、以下のとおりです。</p>



<figure class="wp-block-table"><table><tbody><tr><td>vue.js</td><td>3.2.31</td></tr><tr><td>vue3-sfc-loader</td><td>0.8.4</td></tr></tbody></table></figure>



<h2 class="wp-block-heading"><span id="toc2">Vueのコンポーネントとは？</span></h2>



<p>Vueでは、大きなアプリケーション（下図の左側）を小さな部品の組み合わせで構成（下図の右側）することができます。<br>この小さな部品（下図の緑色の箱）に相当するのがコンポーネントです。</p>



<figure class="wp-block-image size-full"><a href="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2025/10/e775493df2d4f350fa43ae9e3ce78400.png"><img loading="lazy" decoding="async" width="1406" height="544" src="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2025/10/e775493df2d4f350fa43ae9e3ce78400.png" alt="" class="wp-image-14533" srcset="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2025/10/e775493df2d4f350fa43ae9e3ce78400.png 1406w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2025/10/e775493df2d4f350fa43ae9e3ce78400-500x193.png 500w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2025/10/e775493df2d4f350fa43ae9e3ce78400-800x310.png 800w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2025/10/e775493df2d4f350fa43ae9e3ce78400-300x116.png 300w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2025/10/e775493df2d4f350fa43ae9e3ce78400-768x297.png 768w" sizes="(max-width: 1406px) 100vw, 1406px" /></a></figure>



<p>詳しくは、Vueの公式ドキュメント「<a rel="noopener noreferrer" href="https://v3.ja.vuejs.org/guide/introduction.html#%E3%82%B3%E3%83%B3%E3%83%9B%E3%82%9A%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%AB%E3%82%88%E3%82%8B%E6%A7%8B%E6%88%90" target="_blank">コンポーネントによる構成<span class="fa fa-external-link external-icon anchor-icon"></span></a>」を参照してください。</p>



<h2 class="wp-block-heading"><span id="toc3">単一ファイルコンポーネントとは？</span></h2>



<p><a rel="noopener noreferrer" href="https://v3.ja.vuejs.org/guide/single-file-component.html" target="_blank">単一ファイルコンポーネント<span class="fa fa-external-link external-icon anchor-icon"></span></a>（Single-File Component：以後SFCと呼ぶ）は、Vueを使う上で、とても便利な仕組みです。</p>
<p>SFCは、下図のように、「JavaScript：&lt;script&gt;タグ」「HTML：&lt;template&gt;タグ」「CSS：&lt;style&gt;タグ」を1つにまとめて記述したファイルのことです。<br>このファイルの拡張子は「*.vue」で、SFCのことを、別名「*.vue」ファイルということがあります。</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="601" height="541" src="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/SFC.png" alt="" class="wp-image-10606" srcset="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/SFC.png 601w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/SFC-500x450.png 500w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/SFC-300x270.png 300w" sizes="(max-width: 601px) 100vw, 601px" /></figure>



<p>SFCの「JavaScript：&lt;script&gt;タグ」でコンポーネントの動作や処理を記述することができ、「HTML：&lt;template&gt;タグ」「CSS：&lt;style&gt;タグ」でコンポーネントの外観を指定することができます。<br>つまり、「*.vue」ファイル1つで、コンポーネントの動作と外観が規定できるということです。</p>



<p>大きなアプリケーションを小さなコンポーネントに分解すれば、ソースコードの可読性も上がりますし、メンテナンスも容易になります。</p>



<p>また、このSFCに汎用性を持たせて、再利用できるように作っておけば、いろいろなアプリケーションで流用できます。</p>



<h2 class="wp-block-heading"><span id="toc4">ブラウザ環境で単一ファイルコンポーネントを使うには？</span></h2>



<p>とっても便利なSFCなのですが、ブラウザ環境で動作するJavaScriptでは、「*.vue」ファイルをそのまま読み込むことができません。</p>



<div class="wp-block-cocoon-blocks-icon-box common-icon-box block-box information-box">
<p>サーバーの「Node.js」にインストールした「weback」や「Vue CLI」、「Vite」などの開発環境では、「*.vue」ファイルを直接読み込むことができます。</p>
</div>



<p>Vueの便利な機能の1つであるSFCが使えないのは、とても残念です。</p>



<p>ところが、「<a rel="noopener noreferrer" href="https://github.com/FranckFreiburger/vue3-sfc-loader" target="_blank">vue3-sfc-loader<span class="fa fa-external-link external-icon anchor-icon"></span></a>」というライブラリを使えば、ブラウザ環境でも「*.vue」ファイルを直接読み込んで、SFCの仕組みを活用することができます。</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Vue3/Vue2 Single File Component loader.</p>



<p>Load .vue files dynamically at runtime from your html/js. No node.js environment, no (webpack) build step needed.</p>
</blockquote>



<p>上記「vue3-sfc-loader」の概要にも書いてあるように、"<span class="marker-under-red">No node.js environment, no (webpack) build step needed.</span>"、つまり、「Node.js」も「webpack」も無いブラウザ環境で、VueのSFCを使えるようになります。<br>ブラウザ環境で、SFCがサクッと使えるようになると、WordPressサイトのような「Node.js」の無い環境で、Vueの便利さと簡便さが最大限発揮できると思います。</p>



<p>「vue3-sfc-loader」のオプションを工夫すると、読み込んだ「*.vue」ファイルから、別の「*.vue」ファイルを読み込んだり、外部サイトのJavaScriptライブラリをインポートすることもできます。</p>



<h2 class="wp-block-heading"><span id="toc5">「vue3-sfc-loader」の使い方</span></h2>



<p>実際に、「vue3-sfc-loader」を使って、SFCを読み込んでみましょう。</p>



<script src="https://cdn.jsdelivr.net/npm/vue@3.2.31/dist/vue.global.js"></script>

<div id="app"></div>

<script type="module">
    ////////////////////////////////////////////////////////////////////////////////
    // vue3-sfc-loader モジュール
    ////////////////////////////////////////////////////////////////////////////////
    import { loadModule } from "https://cdn.jsdelivr.net/npm/vue3-sfc-loader@0.8.4/dist/vue3-sfc-loader.esm.js";

    ////////////////////////////////////////////////////////////////////////////////
    // vue3-sfc-loader オプション
    // SFCファイルから外部のモジュールをimportできるオプション
    // 参考：https://github.com/FranckFreiburger/vue3-sfc-loader/issues/14#issuecomment-908849863
    ////////////////////////////////////////////////////////////////////////////////
    const vue3_sfc_loader_options = {
        moduleCache: { vue: Vue },
        getFile(url) {
            url = /.*?.js|.mjs|.css|.less|.vue$/.test(url)
                ? url
                : `${url}.vue`;
            const type = /.*?.js|.mjs$/.test(url)
                ? ".mjs"
                : /.*?.vue$/.test(url)
                ? ".vue"
                : /.*?.css$/.test(url)
                ? ".css"
                : ".vue";
            const getContentData = (asBinary) =>
                fetch(url).then((res) =>
                    !res.ok
                        ? Promise.reject(url)
                        : asBinary
                        ? res.arrayBuffer()
                        : res.text()
                );
            return { getContentData: getContentData, type: type };
        },
        addStyle(textContent) {
            let styleElement = document.createElement("style");
            document.head.insertBefore(
                Object.assign(styleElement, { textContent }),
                document.head.getElementsByTagName("style")[0] || null
            );
        },
        handleModule(type, getContentData, path, options) {
            switch (type) {
                case ".css":
                    return options.addStyle(getContentData(false));
                case ".less":
                    console.error(".......");
            }
        },
        log(type, ...args) {
            console.log(type, ...args);
        },
    };

    ////////////////////////////////////////////////////////////////////////////////
    // Vue.js アプリケーションインスタンス
    ////////////////////////////////////////////////////////////////////////////////
    const app = Vue.createApp({
        components: {
            "hello-world": Vue.defineAsyncComponent(() =>
                loadModule(
                    "../wp-content/themes/cocoon-child-master/vue-components/hello_world.vue",
                    vue3_sfc_loader_options
                )
            ),
        },
        template: `<hello-world />`,
    });
    app.mount("#app");
</script>



<p>どうでしょうか？<br>赤い文字で「<strong style="color:red">Hello World!</strong>」と表示されましたか？</p>



<p>「<strong style="color:red">Hello World!</strong>」と表示されている部分には、WordPressのブロックエディタで「カスタム HTML」ブロックを配置しています。</p>



<p>「カスタム HTML」ブロックには、以下のHTMLコードを入力します。</p>



<div class="hcb_wrap html"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue@3.2.31/dist/vue.global.js&quot;&gt;&lt;/script&gt;

&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;

&lt;script type=&quot;module&quot;&gt;
    ////////////////////////////////////////////////////////////////////////////////
    // vue3-sfc-loader モジュール
    ////////////////////////////////////////////////////////////////////////////////
    import { loadModule } from &quot;https://cdn.jsdelivr.net/npm/vue3-sfc-loader@0.8.4/dist/vue3-sfc-loader.esm.js&quot;;

    ////////////////////////////////////////////////////////////////////////////////
    // vue3-sfc-loader オプション
    // SFCファイルから外部のモジュールをimportできるオプション
    // 参考：https://github.com/FranckFreiburger/vue3-sfc-loader/issues/14#issuecomment-908849863
    ////////////////////////////////////////////////////////////////////////////////
    const vue3_sfc_loader_options = {
        moduleCache: { vue: Vue },
        getFile(url) {
            url = /.*?.js|.mjs|.css|.less|.vue$/.test(url)
                ? url
                : `${url}.vue`;
            const type = /.*?.js|.mjs$/.test(url)
                ? &quot;.mjs&quot;
                : /.*?.vue$/.test(url)
                ? &quot;.vue&quot;
                : /.*?.css$/.test(url)
                ? &quot;.css&quot;
                : &quot;.vue&quot;;
            const getContentData = (asBinary) =&gt;
                fetch(url).then((res) =&gt;
                    !res.ok
                        ? Promise.reject(url)
                        : asBinary
                        ? res.arrayBuffer()
                        : res.text()
                );
            return { getContentData: getContentData, type: type };
        },
        addStyle(textContent) {
            let styleElement = document.createElement(&quot;style&quot;);
            document.head.insertBefore(
                Object.assign(styleElement, { textContent }),
                document.head.getElementsByTagName(&quot;style&quot;)[0] || null
            );
        },
        handleModule(type, getContentData, path, options) {
            switch (type) {
                case &quot;.css&quot;:
                    return options.addStyle(getContentData(false));
                case &quot;.less&quot;:
                    console.error(&quot;.......&quot;);
            }
        },
        log(type, ...args) {
            console.log(type, ...args);
        },
    };

    ////////////////////////////////////////////////////////////////////////////////
    // Vue.js アプリケーションインスタンス
    ////////////////////////////////////////////////////////////////////////////////
    const app = Vue.createApp({
        components: {
            &quot;hello-world&quot;: Vue.defineAsyncComponent(() =&gt;
                loadModule(
                    &quot;../wp-content/themes/cocoon-child-master/vue-components/hello_world.vue&quot;,
                    vue3_sfc_loader_options
                )
            ),
        },
        template: `&lt;hello-world /&gt;`,
    });
    app.mount(&quot;#app&quot;);
&lt;/script&gt;</code></pre></div>



<h3 class="wp-block-heading"><span id="toc6">コードの解説</span></h3>



<p>では、コードの中身を解説します。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap html"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue@3.2.31/dist/vue.global.js&quot;&gt;&lt;/script&gt;</code></pre></div>



<p>VueをCDNサイト「<a href="https://cdn.jsdelivr.net/npm/vue@next/dist/">https://cdn.jsdelivr.net<span class="fa fa-external-link external-icon anchor-icon"></span></a>」からインポートします。<br>"vue@3.2.31"なので、メジャーバージョンが「3」です。<br>なので、Vue3を読み込んでいます。</p>



<p>投稿やページの最初に1回インポートすれば、それ以降、Vueのメソッド（関数）は、"Vue.createApp();"のように「Vue.func()」で利用できます。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap html"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;</code></pre></div>



<p>Vueのアプリケーションインスタンスをマウントする&lt;div&gt;タグを"app"というidで配置します。<br>この&lt;div&gt;要素が、この後に読み込むSFC、"hello_world.vue"で置き換えられます。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap html"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;script type=&quot;module&quot;&gt;
　…
&lt;script&gt;</code></pre></div>



<p>&lt;script type="module"&gt;～&lt;/script&gt;が、SFCを読み込むJavaScriptになります。<br>JavaScriptでimport文を使うので、「type="module"」にします。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap javascript"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>    ////////////////////////////////////////////////////////////////////////////////
    // vue3-sfc-loader モジュール
    ////////////////////////////////////////////////////////////////////////////////
    import { loadModule } from &quot;https://cdn.jsdelivr.net/npm/vue3-sfc-loader@0.8.4/dist/vue3-sfc-loader.esm.js&quot;;
</code></pre></div>



<p>「vue3-sfc-loader」をCDNサイト「<a href="https://cdn.jsdelivr.net/npm/vue@next/dist/">https://cdn.jsdelivr.net<span class="fa fa-external-link external-icon anchor-icon"></span></a>」からインポートします。<br>ファイル名が"vue3-sfc-loader.esm.js"になっていて、"esm"という文字列が入っています。<br>これは、import文でインポートできる「ESモジュール」であることを示しています。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap javascript"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>    ////////////////////////////////////////////////////////////////////////////////
    // vue3-sfc-loader オプション
    // SFCファイルから外部のモジュールをimportできるオプション
    // 参考：https://github.com/FranckFreiburger/vue3-sfc-loader/issues/14#issuecomment-908849863
    ////////////////////////////////////////////////////////////////////////////////
    const vue3_sfc_loader_options = {
        moduleCache: { vue: Vue },
        getFile(url) {
            url = /.*?.js|.mjs|.css|.less|.vue$/.test(url)
                ? url
                : `${url}.vue`;
            const type = /.*?.js|.mjs$/.test(url)
                ? &quot;.mjs&quot;
                : /.*?.vue$/.test(url)
                ? &quot;.vue&quot;
                : /.*?.css$/.test(url)
                ? &quot;.css&quot;
                : &quot;.vue&quot;;
            const getContentData = (asBinary) =&gt;
                fetch(url).then((res) =&gt;
                    !res.ok
                        ? Promise.reject(url)
                        : asBinary
                        ? res.arrayBuffer()
                        : res.text()
                );
            return { getContentData: getContentData, type: type };
        },
        addStyle(textContent) {
            let styleElement = document.createElement(&quot;style&quot;);
            document.head.insertBefore(
                Object.assign(styleElement, { textContent }),
                document.head.getElementsByTagName(&quot;style&quot;)[0] || null
            );
        },
        handleModule(type, getContentData, path, options) {
            switch (type) {
                case &quot;.css&quot;:
                    return options.addStyle(getContentData(false));
                case &quot;.less&quot;:
                    console.error(&quot;.......&quot;);
            }
        },
        log(type, ...args) {
            console.log(type, ...args);
        },
    };</code></pre></div>



<p>"vue3_sfc_loader_options"は、「vue3-sfc-loader」でSFCを読み込むときのオプションです。<br>読み込んだSFCファイルから外部のモジュールをimportできるオプションになっています。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-reference-link">

<a rel="noopener noreferrer" href="https://github.com/FranckFreiburger/vue3-sfc-loader/issues/14#issuecomment-908849863" title="Is it possible to import from an ES6 module in a component (SFC) ? ?? Issue #14 ?? FranckFreiburger/vue3-sfc-loader" class="blogcard-wrap external-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard external-blogcard eb-left cf"><div class="blogcard-label external-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail external-blogcard-thumbnail"><img loading="lazy" decoding="async" src="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/cocoon-resources/blog-card-cache/e8ba901917fc72ce3d25524e176ef712.jpg" alt="" class="blogcard-thumb-image external-blogcard-thumb-image" width="160" height="90" /></figure><div class="blogcard-content external-blogcard-content"><div class="blogcard-title external-blogcard-title">Is it possible to import from an ES6 module in a component (SFC) ? ?? Issue #14 ?? FranckFreiburger/vue3-sfc-loader</div><div class="blogcard-snippet external-blogcard-snippet">Hi, First I wan&#039;t to thank you for this librairy which is going to be very useful for me. I can&#039;t manage to import from ...</div></div><div class="blogcard-footer external-blogcard-footer cf"><div class="blogcard-site external-blogcard-site"><div class="blogcard-favicon external-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://github.com/FranckFreiburger/vue3-sfc-loader/issues/14" alt="" class="blogcard-favicon-image external-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain external-blogcard-domain">github.com</div></div></div></div></a>
</div>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap javascript"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>    ////////////////////////////////////////////////////////////////////////////////
    // Vue.js アプリケーションインスタンス
    ////////////////////////////////////////////////////////////////////////////////
    const app = Vue.createApp({
        components: {
            &quot;hello-world&quot;: Vue.defineAsyncComponent(() =&gt;
                loadModule(
                    &quot;../wp-content/themes/cocoon-child-master/vue-components/hello_world.vue&quot;,
                    vue3_sfc_loader_options
                )
            ),
        },
        template: `&lt;hello-world /&gt;`,
    });
    app.mount(&quot;#app&quot;);</code></pre></div>



<p>"Vue.createApp"で、Vueのアプリケーションインスタンスを作成した後、"app.mount("#app");"で、最初に作成した&lt;div&gt;タグに、作成したアプリケーションインスタンスをマウントしています。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap javascript"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>                loadModule(
                    &quot;../wp-content/themes/cocoon-child-master/vue-components/hello_world.vue&quot;,
                    vue3_sfc_loader_options
                )
</code></pre></div>



<p>「vue3-sfc-loader」の"loadModule"関数で、SFCファイルを読み込みます。<br>今回は、"hello_world.vue"という名前のSFCファイルを"../wp-content/themes/cocoon-child-master/vue-components/"フォルダの下に置いています。</p>



<p>「ちょいプラ素材」のブログは、WordPressのテーマに「<a rel="noopener noreferrer" href="https://wp-cocoon.com/" target="_blank">Cocoon<span class="fa fa-external-link external-icon anchor-icon"></span></a>」を使っています。<br>なので、「<a rel="noopener noreferrer" href="https://wp-cocoon.com/" target="_blank">Cocoon<span class="fa fa-external-link external-icon anchor-icon"></span></a>」の子テーマ「<a rel="noopener noreferrer" href="https://wp-cocoon.com/downloads/#toc3" target="_blank">cocoon-child-master<span class="fa fa-external-link external-icon anchor-icon"></span></a>」の下に"vue-components"というフォルダを作りました。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap javascript"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>        components: {
            &quot;hello-world&quot;: Vue.defineAsyncComponent(() =&gt;</code></pre></div>



<p>読み込んだSFCは、"hello-world"という名前のコンポーネントになります。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="hcb_wrap javascript"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>        template: `&lt;hello-world /&gt;`,</code></pre></div>



<p>"hello-world"コンポーネントを&lt;hello-world&gt;タグでHTML要素として配置します。</p>



<h3 class="wp-block-heading"><span id="toc7">"hello_world.vue"の中身</span></h3>



<p>"hello_world.vue"の中身は、Vueの公式ガイド「<a rel="noopener noreferrer" href="https://v3.ja.vuejs.org/guide/single-file-component.html" target="_blank">単一ファイルコンポーネント<span class="fa fa-external-link external-icon anchor-icon"></span></a>」で紹介されている単純なテンプレート構文の例のSFCです。</p>



<div class="hcb_wrap html"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;script&gt;
export default {
  data() {
    return {
      greeting: &#39;Hello World!&#39;
    }
  }
}
&lt;/script&gt;

&lt;template&gt;
  &lt;p class=&quot;greeting&quot;&gt;{{ greeting }}&lt;/p&gt;
&lt;/template&gt;

&lt;style&gt;
.greeting {
  color: red;
  font-weight: bold;
}
&lt;/style&gt;</code></pre></div>



<p>"greeting"というテンプレートを"color: red;"と"font-weight: bold;"のスタイルで表示するというものです。<br>"greeting"というテンプレートの文字列は、"Hello World!"です。</p>



<h2 class="wp-block-heading"><span id="toc8">まとめ</span></h2>



<p>「vue3-sfc-loader」ライブラリを使えば、WordPressの「カスタム HTML」ブロックから、VueのSFCを読み込むことができます。<br>「カスタム HTML」ブロックには、SFCのロード処理だけを書いて、実際にやりたい表示や処理は、SFC（1つの「*.vue」ファイル）にまとめることができます。<br>さらに凝った表示や処理をさせたい場合は、適宜、いくつかのSFCに分割すれば良いでしょう。</p>



<p>この方法で、WordPressサイトに簡単にVueを導入し、WordPressサイトのページ中に、複雑な表示や処理を実装することができます。</p>



<p>次は、もう少し面白いSFCの例として、WordPressの投稿に「<a rel="noopener noreferrer" href="https://www.chartjs.org/" target="_blank">Chart.js<span class="fa fa-external-link external-icon anchor-icon"></span></a>」のチャート（グラフ）を表示してみましょう。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-related">

<a href="https://vitorec.co.jp/choi-plus-sozai/wordpress%e3%81%ae%e6%8a%95%e7%a8%bf%e3%81%abvue3%e3%81%aesfc%e3%82%92%e8%aa%ad%e3%81%bf%e8%be%bc%e3%82%93%e3%81%a7chart-js%e3%81%ae%e3%83%81%e3%83%a3%e3%83%bc%e3%83%88%e3%82%92%e8%a1%a8%e7%a4%ba/" title="WordPressの投稿にVue3のSFCを読み込んでChart.jsのチャートを表示する" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/Chartjs-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/Chartjs-160x90.png 160w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/Chartjs-120x68.png 120w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/Chartjs-320x180.png 320w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">WordPressの投稿にVue3のSFCを読み込んでChart.jsのチャートを表示する</div><div class="blogcard-snippet internal-blogcard-snippet">WordPressの投稿に「Chart.js」をラップしたVueのSFCを読み込み、チャート（グラフ）を表示します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://vitorec.co.jp/choi-plus-sozai" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">vitorec.co.jp</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2024.05.26</div></div></div></div></a>
</div>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>


]]></content:encoded>
					
					<wfw:commentRss>https://vitorec.co.jp/choi-plus-sozai/wordpress%e3%81%ae%e3%82%b5%e3%82%a4%e3%83%88%e3%81%a7vue3%e3%81%ae%e5%8d%98%e4%b8%80%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%82%b3%e3%83%b3%e3%83%9d%e3%83%bc%e3%83%8d%e3%83%b3%e3%83%88%e3%82%92/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>そろそろVue3を使ってみるか</title>
		<link>https://vitorec.co.jp/choi-plus-sozai/%e3%81%9d%e3%82%8d%e3%81%9d%e3%82%8dvue3%e3%82%92%e4%bd%bf%e3%81%a3%e3%81%a6%e3%81%bf%e3%82%8b%e3%81%8b/</link>
					<comments>https://vitorec.co.jp/choi-plus-sozai/%e3%81%9d%e3%82%8d%e3%81%9d%e3%82%8dvue3%e3%82%92%e4%bd%bf%e3%81%a3%e3%81%a6%e3%81%bf%e3%82%8b%e3%81%8b/#respond</comments>
		
		<dc:creator><![CDATA[管理者]]></dc:creator>
		<pubDate>Sat, 02 Apr 2022 14:25:57 +0000</pubDate>
				<category><![CDATA[Vue3]]></category>
		<category><![CDATA[ブログサイトの立ち上げ方]]></category>
		<guid isPermaLink="false">https://vitorec.co.jp/choi-plus-sozai/?p=10511</guid>

					<description><![CDATA[目次 Vue.jsは、とっても楽しいVue3へ移行使いたいのはローカルのブラウザ環境WordPressで作成されたWebサイトが表示されるまでの流れサーバー側にインストールしたNode.jsでJavaScriptを使う場 [&#8230;]]]></description>
										<content:encoded><![CDATA[

  <div id="toc" class="toc tnt-number-detail toc-center tnt-number_detail border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-12" checked><label class="toc-title" for="toc-checkbox-12">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">Vue.jsは、とっても楽しい</a></li><li><a href="#toc2" tabindex="0">Vue3へ移行</a></li><li><a href="#toc3" tabindex="0">使いたいのはローカルのブラウザ環境</a><ol><li><a href="#toc4" tabindex="0">WordPressで作成されたWebサイトが表示されるまでの流れ</a></li><li><a href="#toc5" tabindex="0">サーバー側にインストールしたNode.jsでJavaScriptを使う場合</a></li><li><a href="#toc6" tabindex="0">クライアント側のブラウザで動作するVueとは？</a></li><li><a href="#toc7" tabindex="0">CDNからVueを読み込む</a></li></ol></li><li><a href="#toc8" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2 class="wp-block-heading"><span id="toc1">Vue.jsは、とっても楽しい</span></h2>



<p>2017年頃、ネットでReactとかVueといったJavaScriptのフレームワークの話題を頻繁に目にするようになって、自分のWordPressサイトのフロントエンドでも、ReactかVueを使ってみたいと思い始めました。</p>



<p>ReactにするかVueにするか、いろいろ調べた結果、</p>



<ul class="wp-block-list"><li>既存のJavaScriptのプログラムに少しずつ導入できそうなこと</li><li><a rel="noopener noreferrer" href="https://jp.vuejs.org/v2/guide/" target="_blank">Vue2の日本語サイト<span class="fa fa-external-link external-icon anchor-icon"></span></a>のイントロダクションの説明がとてもわかりやすかったこと</li></ul>



<p>から、Vue.js（当時のバージョンは、2.xだったので、Vue2と呼ぶ）を使い始めました。</p>



<p>Vue2を使うまでは、JQueryを使ってHTMLの要素を動的に操作したりしていましたが、いざ、Vue2を使い始めると、</p>



<p>「なんて便利なの！」<br>「もっと早く使えば良かった。」</p>



<p>という感じで、ドハマりしてしまいました。</p>



<p>何より、JavaScriptの変数やプロパティーが変わると、更新が必要なDOMが自動で置き換わるリアクティブな動作が心地いいんです。</p>



<p>状態の変化に応じて、自分でHTML要素をJQueryで変更する面倒な作業には、もう戻れません。</p>



<p>「<a href="https://www.kabanoki.net/category/vue-js/">カバの樹<span class="fa fa-external-link external-icon anchor-icon"></span></a>」さんのサイトなどで紹介されているVueのライブラリも便利そうなものが多く、気に入ったVueライブラリを自分のサイトに組み込むのが楽しい作業になりました。</p>



<h2 class="wp-block-heading"><span id="toc2">Vue3へ移行</span></h2>



<p>Vue.jsは、2020年の9月にメジャーバージョンが2.xから3.0にアップし、さまざまな改良が加えられました。</p>



<p>いろいろネットの情報を調べてみると、Vue.js本体を2.xから3.0に単純に差し替えるだけではダメで、自分の書いたJavaScriptのプログラムを変更しないといけないことがわかりました。</p>



<p>以下のように、Vueアプリケーションを組み込む、最初のコードから違います。</p>



<div class="hcb_wrap javascript"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>// Vue2の場合
var app = new Vue({
  el: &#39;#app&#39;,
    …
})</code></pre></div>



<div class="hcb_wrap"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>// Vue3の場合
Vue.createApp(Counter).mount(&#39;#app&#39;)</code></pre></div>



<p>ということで、ちょっと面倒臭くなり、しばらく放っておきました。</p>



<p>ただ、HTMLのテーブルにいろいろな機能を追加するために、ずっと利用させてもらってきたJQueryの「<a href="https://mottie.github.io/tablesorter/docs/">teblesorter<span class="fa fa-external-link external-icon anchor-icon"></span></a>」というライブラリを、テーブル用Vueライブラリ「<a rel="noopener noreferrer" href="https://borisflesch.github.io/vue-good-table-next/" target="_blank">vue-good-table-next<span class="fa fa-external-link external-icon anchor-icon"></span></a>」へ置き換えるのを機に、Vue3に移行することにしました。</p>



<h2 class="wp-block-heading"><span id="toc3">使いたいのはローカルのブラウザ環境</span></h2>



<p>ここで一つ注意があります。</p>



<p>ネットでVueの情報を閲覧すると、そのほとんどが、サーバー側に<a rel="noopener noreferrer" href="https://nodejs.org/ja/" target="_blank">Node.js<span class="fa fa-external-link external-icon anchor-icon"></span></a>をインストールして、その<a rel="noopener noreferrer" href="https://nodejs.org/ja/" target="_blank">Node.js<span class="fa fa-external-link external-icon anchor-icon"></span></a>の環境でVueを実行させる話です。</p>



<div class="wp-block-cocoon-blocks-icon-box common-icon-box block-box information-box">
<p>Node.jsは、WindowsやMACなど、手元（ローカル）のPCにインストールすることもできます。<br>ただし、ローカルのPCにインストールしたNode.jsの環境は、あくまでサーバーとしての位置づけです。<br>ローカルPCの中に、仮想のサーバーを作るイメージです。</p>
</div>



<p>この「ちょいプラ素材」のブログで取り上げるのは、サーバー側にインストールした<a rel="noopener noreferrer" href="https://nodejs.org/ja/" target="_blank">Node.js<span class="fa fa-external-link external-icon anchor-icon"></span></a>環境の話ではなく、手元（ローカル）のブラウザ環境でVue3を利用する方法です。</p>



<h3 class="wp-block-heading"><span id="toc4">WordPressで作成されたWebサイトが表示されるまでの流れ</span></h3>



<ul class="wp-block-list"><li><strong>クライアント側</strong>：手元（ローカル）のブラウザ環境</li><li><strong>サーバー側</strong>：サーバー環境</li></ul>



<p>の区別を理解するために、WordPressで作成されたWebサイトの情報やコンテンツが、ローカルPCのブラウザに表示されるまでの流れを説明します。</p>



<p>この「ちょいプラ素材」のブログも、WordPressを利用したWebサイトです。<br>皆さんの使っているブラウザから、「ちょいプラ素材」にアクセスしたとき、「ちょいプラ素材」のコンテンツがブラウザに表示されるまでの流れを下図で説明します。</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1131" height="784" src="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/9f66f4eeb893681239eb177b24b14459.png" alt="" class="wp-image-10534" srcset="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/9f66f4eeb893681239eb177b24b14459.png 1131w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/9f66f4eeb893681239eb177b24b14459-500x347.png 500w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/9f66f4eeb893681239eb177b24b14459-800x555.png 800w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/9f66f4eeb893681239eb177b24b14459-300x208.png 300w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/9f66f4eeb893681239eb177b24b14459-768x532.png 768w" sizes="(max-width: 1131px) 100vw, 1131px" /></figure>



<ol class="marusuuji wp-block-list"><li>ブラウザから「ちょいプラ素材」のURLを指定してWebサーバーにアクセスします。<br>　</li><li>Webサーバーは、URLを解釈して、URLに応じたPHPプログラムを実行します。<br><span class="fz-14px">Webサーバーには、Linuxサーバーで利用されるAPACHE、NGINX、OpenLiteSpeed</span><span class="fz-14px">や</span><span class="fz-14px">、Windowsサーバーで利用されるIISなどがあります。</span><br>　</li><li>PHPプログラムは、MySQLを経由して、データベースに保存されているコンテンツ（文章やデータ）を読み出します。<br><span class="fz-14px">MariaDBなどMySQL互換のデータベースサーバーが使われることもあります。</span><br>　</li><li>データベースから読み出されたコンテンツは、PHPプログラムによって処理され、Webサーバーを通して、HTML / CSS / JavaScript の形式でクライアント側に送られます。<br>　</li><li>ブラウザは、クライアント側に送られたHTML / CSS を解釈し、画面に表示します。<br>JavaScriptが含まれるWebページでは、JavaScriptのプログラムを実行します。<span class="fz-16px"><span class="fz-14px"><br>JavaScript（場合によっては、JavaScriptのjQueryライブラリ、JavaScriptのフレームワークのVue.jsなど）を利用するとHTMLの要素を動的に変更することができます。<br>「ちょいプラ素材」では、JavaScriptライブラリやVueライブラリを使って、表やグラフを表示したり、ユーザーインターフェースを構成したりしています。</span></span><br>　</li><li>ブラウザはクライアント側にあるので、ブラウザからサーバー側のデータベースに直接アクセスできません。<br>ユーザーがインターフェースを操作して入力したパラメーターをサーバーに送ったり、表やグラフの元になるデータをサーバーに要求したりする場合は、Ajax通信を使います。<br><span class="fz-16px"><span class="fz-14px">URLを指定したアクセスでは、Webページ全体の表示が更新（リセット）されてしまいますが、Ajax通信を使うと、Webページの表示をリセットしないで、クライアントとサーバーの間でデータのやりとりができます。<br>Ajax通信は、jQueryライブラリやフレームワークのVue.jsにaxiosを組み合わせて利用した方が楽に処理できます。</span></span></li></ol>



<div class="wp-block-group is-layout-flow wp-block-group-is-layout-flow">
<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>
</div>



<p>余談になりますが、2022年4月現在、「<a rel="noopener noreferrer" href="https://w3techs.com/technologies/details/cm-wordpress" target="_blank">W<sup>3</sup>Techs<span class="fa fa-external-link external-icon anchor-icon"></span></a>」の調査データによると、全世界のWebサイトの43%がWordPressを利用しています。<br>コンテンツ管理システムでのシェアは、64.5%です。</p>



<p>これだけ広くWordPressが使われるようになった理由は、WordPressがリリースされた当時、一番メジャーだった以下のサーバーシステムを組み合わせて構成したので、ITエンジニアに抵抗感なく受け入れられたからだと思います。</p>



<ul class="wp-block-list"><li><strong>Webサーバー：</strong>APACHE</li><li><strong>アプリケーションサーバー：</strong>PHP</li><li><strong>データベースサーバー：</strong>MySQL</li></ul>



<h3 class="wp-block-heading"><span id="toc5">サーバー側にインストールしたNode.jsでJavaScriptを使う場合</span></h3>



<p>先ほど、</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>ネットでVueの情報を閲覧すると、そのほとんどが、サーバー側にNode.jsをインストールして、そのNode.jsの環境でVueを実行させる話です。</p></blockquote>



<p>と説明しました。</p>



<p>上図で示したように、WordPressのアプリケーションサーバーは、PHPを使っています。</p>



<p>WordPress以外の一部のWebサイトでは、サーバーにNode.jsをインストールし、サーバー側でもJavaScriptが動作する環境を用意して、この環境で動作するJavaScriptをアプリケーションサーバーとして使うことがあります。</p>



<p>Vueは、JavaScriptのフレームワークですから、当然、サーバー側のNode.js環境でも動作します。<br>ネットに溢れているVueの情報は、サーバー側のNode.js環境の話がほとんどです。</p>



<h3 class="wp-block-heading"><span id="toc6">クライアント側のブラウザで動作するVueとは？</span></h3>



<p>では、「クライアント側のブラウザで動作するVue」とは、どういう話でしょうか？</p>



<p>上図で、</p>



<ol start="4" class="marusuuji-4 wp-block-list"><li>データベースから読み出されたコンテンツは、PHPプログラムによって処理され、Webサーバーを通して、HTML / CSS / JavaScript の形式でクライアント側に送られます。<br>　</li><li>ブラウザは、クライアント側に送られたHTML / CSS を解釈し、画面に表示します。<br>JavaScriptがが含まれるWebページでは、JavaScriptのプログラムを実行します。</li></ol>



<p>と説明しました。</p>



<p>クライアント側に送られたJavaScript（④）は、ブラウザで実行（⑤）されますが、このブラウザで実行されるJavaScriptでも、Vueを動作させることができます。</p>



<p>「クライアント側のブラウザで動作するVue」とは、ブラウザで実行（⑤）されるJavaScriptで、Vueを利用するという意味です。</p>



<h3 class="wp-block-heading"><span id="toc7">CDNからVueを読み込む</span></h3>



<p>ブラウザで動作するJavaScriptでVueを利用するためには、Vue本体（Vue.js）を読み込む必要があります。</p>



<p>上図の④で、Webサーバーから送られるJavaScriptに、Vue本体を含めても良いのですが、</p>



<ul class="wp-block-list"><li>サーバー側の処理や通信トラフィックに負荷がかかる</li><li>個々のサーバーで、Vue本体のバージョン管理をするのは大変</li></ul>



<p>という理由で、実際には行われていません。</p>



<p>では、どうするか？</p>



<p>④で送られるHTMLやJavaScriptの中に、Vue本体を読み込む処理（コード）を埋め込みます。<br>Vue本体を読み込むコードは、1行で書けるほどの小さいサイズなので、④で送られるHTMLやJavaScriptのデータ量はほとんど増えません。</p>



<p>以下に、実際のコードの例を示します。</p>



<div class="hcb_wrap html"><pre class="prism line-numbers lang-html" data-lang="HTML"><code>&lt;!-- HTMLから読み込む場合 --&gt;
&lt;script src=&quot;https://unpkg.com/vue@next&quot;&gt;&lt;/script&gt;</code></pre></div>



<div class="hcb_wrap javascript"><pre class="prism line-numbers lang-js" data-lang="JavaScript"><code>// JavaScriptから読み込む場合
import Vue from &quot;https://cdn.jsdelivr.net/npm/vue@3.2.31/dist/vue.esm-browser.js&quot;;</code></pre></div>



<p>上記のコードで、「3.2.31」は、Vueのバージョンです。<br>メジャーバージョンが「3」なので、Vue3を読み込んでいます。</p>



<p>また、Vue本体を「<a href="https://unpkg.com/browse/vue@3.2.31/dist/">https://unpkg.com<span class="fa fa-external-link external-icon anchor-icon"></span></a>」や「<a href="https://cdn.jsdelivr.net/npm/vue@next/dist/">https://cdn.jsdelivr.net<span class="fa fa-external-link external-icon anchor-icon"></span></a>」といった、CDNサイトから読み込んでいます。</p>



<p>CDNは、「Content Delivery Network：コンテンツデリバリーネットワーク」の略で、</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>ウェブサーバーの負荷を軽減する目的で、ウェブコンテンツを効率的かつスピーディーに配信できるように工夫されたネットワーク</p></blockquote>



<p>の仕組みです。</p>



<h2 class="wp-block-heading"><span id="toc8">まとめ</span></h2>



<p>今後、「ちょいプラ素材」では、ローカルのブラウザ環境でVue3を使う方法を説明します。</p>



<p>具体的には、</p>



<ul class="wp-block-list"><li>ブラウザ環境で、SFC（Single-File Component：単一ファイルコンポーネント、別名 *.vueファイル）を使う方法</li><li>美しいグラフを作成できる有名なJavaScriptライブラリ「<a rel="noopener noreferrer" href="https://www.chartjs.org/" target="_blank">Chart.js<span class="fa fa-external-link external-icon anchor-icon"></span></a>」をVue3で使う方法</li><li>テーブル用の高機能なVueライブラリ「<a rel="noopener noreferrer" href="https://borisflesch.github.io/vue-good-table-next/" target="_blank">vue-good-table-next<span class="fa fa-external-link external-icon anchor-icon"></span></a>」をVue3で使う方法</li></ul>



<p>などを紹介しようと思います。</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-related">

<a href="https://vitorec.co.jp/choi-plus-sozai/wordpress%e3%81%ae%e3%82%b5%e3%82%a4%e3%83%88%e3%81%a7vue3%e3%81%ae%e5%8d%98%e4%b8%80%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%82%b3%e3%83%b3%e3%83%9d%e3%83%bc%e3%83%8d%e3%83%b3%e3%83%88%e3%82%92/" title="WordPressのサイトでVue3の単一ファイルコンポーネントを使う" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/SFC-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/SFC-160x90.png 160w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/SFC-120x68.png 120w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/SFC-320x180.png 320w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">WordPressのサイトでVue3の単一ファイルコンポーネントを使う</div><div class="blogcard-snippet internal-blogcard-snippet">「vue3-sfc-loader」を使うと、「Node.js」が無いブラウザ環境でもVue3の単一ファイルコンポーネントを使うことができます。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://vitorec.co.jp/choi-plus-sozai" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">vitorec.co.jp</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2025.10.18</div></div></div></div></a>
</div>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-related">

<a href="https://vitorec.co.jp/choi-plus-sozai/wordpress%e3%81%ae%e6%8a%95%e7%a8%bf%e3%81%abvue3%e3%81%aesfc%e3%82%92%e8%aa%ad%e3%81%bf%e8%be%bc%e3%82%93%e3%81%a7chart-js%e3%81%ae%e3%83%81%e3%83%a3%e3%83%bc%e3%83%88%e3%82%92%e8%a1%a8%e7%a4%ba/" title="WordPressの投稿にVue3のSFCを読み込んでChart.jsのチャートを表示する" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/Chartjs-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/Chartjs-160x90.png 160w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/Chartjs-120x68.png 120w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/Chartjs-320x180.png 320w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">WordPressの投稿にVue3のSFCを読み込んでChart.jsのチャートを表示する</div><div class="blogcard-snippet internal-blogcard-snippet">WordPressの投稿に「Chart.js」をラップしたVueのSFCを読み込み、チャート（グラフ）を表示します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://vitorec.co.jp/choi-plus-sozai" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">vitorec.co.jp</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2024.05.26</div></div></div></div></a>
</div>



<div class="wp-block-cocoon-blocks-blogcard blogcard-type bct-related">

<a href="https://vitorec.co.jp/choi-plus-sozai/wordpress%e3%81%ae%e6%8a%95%e7%a8%bf%e3%81%ab%e3%82%bd%e3%83%bc%e3%83%88%e3%82%84%e3%83%9a%e3%83%bc%e3%82%b8%e3%83%8d%e3%83%bc%e3%82%b7%e3%83%a7%e3%83%b3%e3%81%ae%e6%a9%9f%e8%83%bd%e3%82%92%e6%8c%81/" title="WordPressの投稿にソートやページネーションの機能を持ったテーブルを実装する" class="blogcard-wrap internal-blogcard-wrap a-wrap cf" target="_blank"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="90" src="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/vue-good-table-next-160x90.png" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/vue-good-table-next-160x90.png 160w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/vue-good-table-next-120x68.png 120w, https://vitorec.co.jp/choi-plus-sozai/wp-content/uploads/2022/04/vue-good-table-next-320x180.png 320w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">WordPressの投稿にソートやページネーションの機能を持ったテーブルを実装する</div><div class="blogcard-snippet internal-blogcard-snippet">VueのSFCを介して「vue-good-table-next」を使うと、WordPressの投稿に多機能なテーブルを手軽に実装できます。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img loading="lazy" decoding="async" src="https://www.google.com/s2/favicons?domain=https://vitorec.co.jp/choi-plus-sozai" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">vitorec.co.jp</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2024.07.25</div></div></div></div></a>
</div>



<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>


]]></content:encoded>
					
					<wfw:commentRss>https://vitorec.co.jp/choi-plus-sozai/%e3%81%9d%e3%82%8d%e3%81%9d%e3%82%8dvue3%e3%82%92%e4%bd%bf%e3%81%a3%e3%81%a6%e3%81%bf%e3%82%8b%e3%81%8b/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
