CDN版Vue3で単一ファイルコンポーネント(SFC)の利用するためのモジュール
<vue-sfc-loader.mjs>
////////////////////////////////////////////////////////////////////////////////
// vue3 モジュール
////////////////////////////////////////////////////////////////////////////////
import * as Vue from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
////////////////////////////////////////////////////////////////////////////////
// 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);
},
};
function getFileName(path) {
return path.split('/').pop().split('.').shift();
}
//Appコンポーネントをマウントするラッパー関数
export default function MountSFC(vueFilePath, querySelector="body", model={}){
const app = Vue.createApp({});
if(Array.isArray(vueFilePath)){
vueFilePath.forEach( e => {
app.component(getFileName(e), Vue.defineAsyncComponent(() => loadModule(e, vue3_sfc_loader_options)));
});
}else{
app.component(getFileName(vueFilePath), Vue.defineAsyncComponent(() => loadModule(vueFilePath, vue3_sfc_loader_options)));
}
app.mixin({
methods: {
// 各コンポーネント内の<script>タグ内でグローバル変数を参照するための関数
_model(){
return model;
},
},
computed: {
// 各コンポーネント内の<template>タグ内でグローバル変数を参照するための処置
Model: {
get: function () { return model },
}
}
})
app.mount(querySelector);
}
使用例
<index.html>
<!DOCTYPE html>
<html lang="jp">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test</title>
<script type="module">
import MountSFC from "./vue-sfc-loader.mjs"
MountSFC(["./compo_a_parent.vue","./compo_b.vue"]);
</script>
</head>
<body>
<div>
<compo_a_parent />
</div>
<div>
<compo_b />
</div>
</body>
</html>
<compo_a_parent.vue>
<script setup>
import test from './compo_a_child.vue'
</script>
<template>
<div>コンポーネントA</div>
<input type='text' v-model='message'>
<test :value=message />
</template>
<script>
export default {
data(){
return {
message: 'Hello VueJS!'
}
},
};
</script>
<compo_a_child.vue>
<template>
<div>コンポーネントAから呼び出される子コンポーネント</div>
<div>{{ value }}</div>
<div>
<ul>
<li v-for="(listItem, index) in listItems" :key="index">
{{ listItem }}
</li>
</ul>
</div>
</template>
<script>
export default {
props: {
value: String
},
data() {
return {
listItems: [
"親コンポ―ネントから受け取った値を",
"表示する",
"子コンポーネント",
],
}
},
};
</script>
<compo_b.vue>
<template>
<div>コンポーネントB</div>
</template>
<script>
</script>
結果
この記事が気に入ったらサポートをしてみませんか?