在 Lightning 框架中,如果我们想要使用第三方的组件,可以将它们包含在 Lightning Container 模块中。
Lightning Container 的工作原理
Lightning Container 会将内部的组件包含在一个 iframe 中,并且提供了若干函数让其内部的组件和外部的 Lightning 应用进行通信。
它要求内部的组件是作为“静态资源(static resource)”上传到 Salesforce 中。
它的语法本质上是调用静态资源的 URL 路径。
举个例子,我们已经有了一个 Vue 应用,它的入口文件是 index.html,我们将它上传到 Salesforce 的静态资源,名字叫 “testApp”,那么调用它的方式如下:
<lightning:container src="{!$Resource.testApp + '/index.html'}" />
Lightning Container NPM 包和使用实例
Lightning Container 提供了 NPM 包,可以让第三方组件调用 API,从而和 Lightning 组件进行通信。
我们以两个 Vue-cli 例子程序来说明:
- 如何和 Lightning 组件进行通信
- 如何从第三方组件中调用 Apex 函数
设置 Lightning Container
初始化 Vue-cli 项目,然后安装 NPM 包:
npm install lightning-container --save
在 main.js 文件中加入以下两行:
import LCC from 'lightning-container'
Vue.prototype.$LCC = LCC
这样,我们就可以在其他的组件中引用模块了,语法如下:
this.$LCC
编译 Vue 应用
在命令行中运行以下命令即可将 Vue 的应用编译到 “dist” 文件夹下:
npm run build
然后我们将 “dist” 文件夹下的内容打包成 zip 文件,上传到 Salesforce 中作为静态资源。
Vue-cli 的应用默认的入口是 index.html 文件。
和 Lightning 组件的通信演示
在这个通信的演示程序中,我们要达到的目标是把文字在 Lightning 组件和 Vue 应用中相互发送。
在 Vue 项目中,在 “src/components” 文件夹中新建 Vue 组件,名为 “Messaging.vue”,代码如下:
<template>
<div>
<h3>通信演示</h3>
<div>
发送给 Lightning Component:
<input type="text" id="text-input-to-Lc" class="slds-input" v-model="msgToLC" />
<button id="sendBtn" class="slds-button slds-button--neutral" v-on:click="sendMessage">发送到 Lightning Component</button>
</div>
<div>
从 Lightning Component 接收的信息:
<input type="text" id="text-input-from-Lc" class="slds-input" v-model="msgFromLC" />
</div>
</div>
</template>
<script>
export default {
data () {
return {
msgToLC: '',
msgFromLC: ''
}
},
mounted: function() {
this.$LCC.addMessageHandler(this.receiveMessage); // 使用 addMessageHandler() 函数定义如何接收从 Lightning 组件中传来的数据
},
methods: {
receiveMessage: function(message) {
this.msgFromLC = message.value;
},
sendMessage: function() {
// 使用 sendMessage() 函数发送信息给 Lightning 组件
this.$LCC.sendMessage({name: "Message To LC", value: this.msgToLC})
}
}
}
</script>
在 Vue 项目的 “src/router” 文件夹下,修改 “index.js” 文件,将刚才建立的 Vue 组件定义为默认的路径:
import Messaging from '@/components/Messaging'
export default new Router({
routes: [
{
path: '/',
name: 'Messaging',
component: Messaging
},
]
})
编译 Vue 应用,然后上传到 Salesforce 中,作为静态资源,名为 “VueApplication”。
在 Salesforce 中新建 Lightning 组件:
<aura:component access="global">
<aura:attribute access="private" name="messageToSend" type="String" default=""/>
<aura:attribute access="private" name="messageReceived" type="String" default=""/>
<div>
<lightning:input name="messageToSend" value="{!v.messageToSend}" label="发送给 Vue 应用: "/>
<lightning:button label="Send" onclick="{!c.sendMessage}"/>
<br/>
<lightning:input value="{!v.messageReceived}" label="接收自 Vue 应用: "/>
<br/>
<!-- 使用 lightning:container 来调用静态资源中的 Vue 应用,并定义在收到它的信息时使用的函数 -->
<lightning:container aura:id="vueApp"
src="{!$Resource.vueApplication + '/index.html'}"
onmessage="{!c.handleMessage}"/>
</div>
</aura:component>
定义控制器:
({
/*
* 从 Lightning 组件中发送信息
*/
sendMessage : function(component, event, helper) {
var msg = {
name: "Message From LC",
value: component.get("v.messageToSend")
};
component.find("vueApp").message(msg);
},
/*
* 接收从 Vue 应用中发送的信息
*/
handleMessage: function(component, event, helper) {
var value = event.getParams().payload.value;
component.set("v.messageReceived", value);
},
})
当我们使用这个 Lightning 组件时,它会自动调用 Vue 应用,然后可以将文字在两个应用之间发送和接收。
当我们查看页面的源代码时,可以看到,lightning:container 中的内容被放在了一个 iframe 中,所以我们的 Vue 应用其实是封装起来的。
调用 Apex 函数
在接下来的应用中,我们要从 Vue 应用中调用 Apex 函数。
在 Salesforce 中建立 Apex 函数:
global without sharing class VueController {
@RemoteAction
global static Account[] getAccounts(String searchString) {
return [SELECT Id, Name, Phone, Type, NumberOfEmployees FROM Account Limit 10];
}
}
为了调用 Apex 函数,我们在 Vue 应用中需要一个特殊的设置。在 “dist” 文件夹下建立一个名为 “manifest.json” 的文件,内容如下:
{
"landing-pages" : [
{
"path": "index.html",
"apex-controller": "VueController"
}
]
}
在 Vue 应用中建立一个名为 “AccountList” 的组件:
<template>
<div>
<h3>接收到的数据:</h3>
<ul>
<li v-for="item in accounts">
{{ item.Name }}
</li>
</ul>
</div>
</template>
<script>
export default {
data () {
return {
accounts: [],
}
},
mounted: function() {
this.getAccounts();
},
methods: {
getAccounts: function() {
// 使用 callApex() 函数来调用相应的函数
this.$LCC.callApex("VueController.getAccounts",
{
searchString: ''
},
this.handleResult,
{});
},
handleResult: function(result) {
this.accounts = result;
},
}
}
</script>
这样,在用 lightning:container 在 Lightning 组件中执行 Vue 应用时,Vue 应用会直接调用 Apex 函数,然后给出结果。
与 Locker Service 的比较
Lightning Container 机制和 Locker Service 机制都是对 Lightning 组件的安全进行提高,将不同来源(命名空间等)的组件分别封装。
Lightning Container 是基于 iframe 的,它将第三方的组件或应用封装在 iframe 中,而 Locker Service 则不需要这样,它是将不同的组件放在同一个 DOM 树中,将不同的 DOM 元素封装起来。这是两者最大的不同,从而也决定了它们不同的特性:
- Locker Service 可以利用 Lightning 框架的各种本地功能,而 Lightning Container 中的内容则受到限制,比如只能通过其 NPM 包中提供的 API 函数来进行通信
- Lightning Container 支持的第三方框架比 Locker Service 更多
- Locker Service 中的组件执行速度比 Lightning Container 中的要快
- Locker Service 中的组件和整个 Lightning 框架的外观是一致的,而 Lightning Container 中的内容由于被封装在 iframe 中,在特殊的情况下可能会出现问题