bounty将于明天到期。此问题的答案可获得+100声望奖励。Lowtrux正在寻找规范答案:我希望这个答案能解决主要的问题,即如何使用Vue 3在Vite中生成一个JS文件,该文件可以使用HTML属性来动态更改Vue小部件内部的参数,同时我不能使用Web组件和/或Iframe来加载内容。
我需要制作一个生产交付件(一个小部件,基本上是一个客户服务聊天)以单个.JS文件的形式,用户可以在其中传递一系列HTML数据属性(基本上是我的Vue实现中传递给Widget组件的所有 prop ),以便自定义API端点、WebSocket URL图像路径等。因此,问题是如何从我的Vue实现中生成此类小部件:
我正在使用Vue 3、Vite和Vuex管理WS通信:
<!-- Widget -->
<script src="https://cdn.xyz.xyz/widget.min.js"
data-icon="path_to_icon.jpg"
data-title="Brand support"
data-jwt-url="jwt token url"
data-rubiko-url="another url"
data-company-websocket-url="websocket url"
data-theme="default"
data-brand-id="brand-id">
</script>
<!-- end of Widget -->
首先,我创建了Widget组件,它是哑的--它只显示我从外部提供给它的内容。基本上,一系列的Props在最后将用作来自.JS文件的html属性。有一个传递JWT以验证API的完整过程,但这并不重要:
<template>
<div class="widget-container" v-show="isShow">
<div class="widget-content">
<section class="widget-header"><h1>Hello There !!</h1></section>
<div class="widget-body">
<div class="widget-body-container">
<h3>
👋 Hi there {{ endUserName }} {{ endUserLastName }}! Welcome .
</h3>
<h4>
You are <span v-if="isVip">a Vip user</span>
<span v-else>not a VIP user</span>
</h4>
<h4>The WS connection ID is {{ connectionId }}</h4>
<section class="messageList" v-for="category in categories">
<p>Category ID is: {{ category.id }}</p>
<p>Category Name is: {{ category.name }}</p>
</section>
<section class="messageList" v-for="category in categories">
<p>Category ID is: {{ category.id }}</p>
<p>Category Name is: {{ category.name }}</p>
</section>
</div>
</div>
<section class="widget-input">
<form @submit.prevent="sendMessage" class="chat-form relative mt-6">
<textarea
name="message"
id=""
placeholder="Add your message here.."
aria-label="Send a message"
tabindex="0"
></textarea>
<div class="widget-input-buttons">
<button class="widget-button" type="submit" value="Send">
<i size="16"
><svg
width="16"
height="16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="8"
cy="8"
r="6.725"
stroke="#757575"
stroke-width="1.3"
></circle>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M5.818 7.534a1.1 1.1 0 100-2.2 1.1 1.1 0 000 2.2zm4.364 0a1.1 1.1 0 100-2.2 1.1 1.1 0 000 2.2z"
fill="#757575"
></path>
<path
d="M10 10c-.44.604-1.172 1-2 1-.828 0-1.56-.396-2-1"
stroke="#757575"
stroke-width="1.3"
stroke-linecap="round"
></path>
</svg>
</i>
</button>
</div>
</form>
</section>
</div>
</div>
</template>
<script setup>
const props = defineProps({
categories: Array,
connectionId: String,
endUserName: String,
endUserLastName: String,
endUserEmail: String,
endUserSub: String,
isShow: Boolean,
isVip: Boolean,
});
</script>
然后我有一个负责小部件业务逻辑的容器。为了这个POC的目的,它将连接到一个WebSocket(我有一个Vuex商店,负责与WS的通信和错误处理),检索来自WS的连接ID,然后还将从API检索一些信息作为小部件的内容。
<template>
<Widget
:connectionId="retrieveConnectionId"
:endUserName="name"
:endUserLastName="lastName"
:endUserEmail="email"
:endUserSub="sub"
:isVip="isVip"
:categories="categories"
:isShow="isShow"
/>
<WidgetTrigger @click="isShow = !isShow" :isOpened="!isShow" />
</template>
<script>
import { ref, onMounted } from "vue";
import { Buffer } from "buffer";
import { useActions } from "vuex-composition-helpers";
import { useGetters } from "vuex-composition-helpers";
import Widget from "@/components/Widget.vue";
import WidgetTrigger from "@/components/WidgetTrigger.vue";
export default {
components: {
Widget,
WidgetTrigger,
},
setup() {
const categories = ref([]);
const email = ref("");
const error = ref(null);
const isShow = ref(false);
const isVip = ref();
const lastName = ref("");
const license = ref("");
const name = ref("");
const token = ref("");
const sub = ref("");
const { callWebsocket } = useActions({
callWebsocket: "websocket/processWebsocket",
});
const { retrieveConnectionId } = useGetters({
retrieveConnectionId: "websocket/getConnectionId",
});
const retrieveSignedJWT = async () => {
fetch("http://xyz")
.then(async (response) => {
const data = await response.text();
// check for error response
if (!response.ok) {
// get error message from body or default to response statusText
const error = (data && data.message) || response.statusText;
return Promise.reject(error);
}
let jwt = data;
token.value = data;
decodeToken(jwt);
retrieveCategories();
})
.catch((error) => {
error.value = error;
console.error("There was an error!", error);
});
};
const retrieveCategories = async () => {
fetch(
" http://xyz/categories",
{
method: "GET",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Bearer ${token.value}`,
},
}
)
.then(async (response) => {
const data = await response.json();
// check for error response
if (!response.ok) {
// get error message from body or default to response statusText
const error = (data && data.message) || response.statusText;
return Promise.reject(error);
}
categories.value = data;
})
.catch((error) => {
error.value = error;
console.error("There was an error!", error);
});
};
const decodeToken = async (jwt) => {
let base64Url = jwt.split(".")[1];
let base64 = base64Url.replace("-", "+").replace("_", "/");
let decodedData = JSON.parse(
Buffer.from(base64, "base64").toString("binary")
);
sub.value = decodedData.sub;
name.value = decodedData.name;
lastName.value = decodedData.last_name;
email.value = decodedData.email;
isVip.value = decodedData.is_vip;
};
onMounted(async () => {
await retrieveSignedJWT();
await callWebsocket();
});
return {
categories,
callWebsocket,
decodeToken,
email,
error,
retrieveConnectionId,
retrieveSignedJWT,
retrieveCategories,
isShow,
isVip,
lastName,
license,
name,
retrieveConnectionId,
sub,
token,
};
},
};
</script>
到目前为止,一切都按预期工作,但我找不到反馈,说明哪种方法是正确的,可以将单个.JS文件以小部件的形式提供给小部件,在小部件中我可以使用HTML数据属性,以便小部件可以将它们用作 prop 。
1条答案
按热度按时间bvjxkvbb1#
您可以使用Lit Element
使用的示例是Googlemodel viewer
它使用rollup(查看roolup.config.js)来创建一个js,您可以在html中添加自定义标记,它没有依赖项,因此可以与任何框架一起使用
例如:
我不确定你是否可以用Vue写一个lit元素,但是你仍然可以用rollup来写你的小部件。我不知道Vue,也不知道它是如何独立的(lit元素使用阴影dom,所以它被设计成独立的)