Appearance
常用模板
注意:所有代码示例仅供参考,开发者可根据实际业务需求,自行编写、调整代码逻辑来满足自身的业务需求。
1.模板示例
基础组装样式举例,真实使用中可自定义组装信息流样式。
信息流大图 | 信息流上文下图 | 信息流上图下文 | 信息流组图 | 信息流左图右文 | 信息流左文右图 |
---|---|---|---|---|---|
![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
2.实战示例
该示例主旨是为了方便开发者在此基础上二次开发所以开放了源代码,开发者可以根据自己的需要对该示例进行改动或二次开发。 具体源代码和示例可以以DEMO参考:
2.1 判断逻辑示例(供参考)

2.2 配套示例代码
2.2.1 引入组件示例
html
<import name="feed-composite" src="../template/composite/FeedComposite.ux"></import>
<template>
<div class="wrapper">
<!-- 参数说明:https://quickapp-sdk.vivo.com.cn/site/template.html#_2-3-%E5%B1%9E%E6%80%A7%E8%AF%B4%E6%98%8E -->
<!--
big-pic、
group-pic、
left-pic-right-text、
left-text-right-pic、
top-pic-bottom-text、
top-text-bottom-pic
-->
<feed-composite
position-id="27886a42516544039a5bfc75655ae26d"
media-id="635f3699b4f243aeaf34d7d660df5e85"
is-render="{{isRender}}"
template-big-horizontal="top-pic-bottom-text"
template-big-vertical="big-pic"
template-small="left-pic-right-text"
template-group="group-pic"
@ad-load="onFeedAdLoad"
@ad-error="onAdError"
@ad-click="onAdClick"
></feed-composite>
</div>
</template>
<script>
export default {
data() {
return {
isRender: false // 控制广告是否渲染
}
},
onInit() { },
onFeedAdLoad(evt) {
// 控制广告展示
this.isRender = true;
// 竞价通知根据业务需要发送成功与失败通知
/**
* 发送竞价通知 - 相关文档链接:
* https://quickapp-sdk.vivo.com.cn/site/api.html#_4-1-2%E3%80%81%E5%8F%91%E9%80%81%E7%AB%9E%E4%BB%B7%E9%80%9A%E7%9F%A5
*/
evt.detail.sendNotice(true, evt.detail.adData.price);
// # 竞价失败:发送竞价通知
// evt.detail.sendNotice(false, 7.9, 1);
},
onAdClick(evt) {
console.log("点击事件回调", evt);
},
onAdError(data) {
console.log("报错事件回调", data);
},
// 信息流广告滚动重复曝光需要在当前页面的 onPageScroll(){} 中添加 this.$broadcast("vad-page-scroll", evt); 不添加会影响收入
onPageScroll(evt) {
// 调用$broadcast()事件完成向下传递
this.$broadcast('vad-page-scroll', evt);
},
}
</script>
<style>
.wrapper {
flex-direction: column;
align-items: center;
}
</style>
2.2.1 组件的源代码
UX文件:FeedComposite.ux
html
<import name="vad-button" src="vad-sdk/templates/vadButton.ux"></import>
<import name="vad-ad" src="vad-sdk/templates/vadAd.ux"></import>
<import name="vad-compliance" src="vad-sdk/templates/vadCompliance.ux"></import>
<import name="vad-drawer-compliance" src="vad-sdk/templates/vadDrawerCompliance.ux"></import>
<import name="vad-video" src="vad-sdk/templates/vadVideo.ux"></import>
<import name="vad-frame-feed" src="vad-sdk/templates/vadFrameFeed.ux"></import>
<import name="vad-score" src="vad-sdk/templates/vadScore.ux"></import>
<template>
<div class="{{containerClassName}}">
<vad-frame-feed
position-id="{{positionId}}"
media-id="{{mediaId}}"
custom-style="{{getCustomStyle}}"
is-render="{{isRender}}"
close-position="{{option.closePosition}}"
@ad-load="onFeedAdLoad"
>
<block if="{{renderMode === 'big-pic'}}">
<div class="show-content">
<vad-video
if="{{ adData.materialMode === 'MODE_VIDEO'}}"
id="vadVideo"
position-id="{{adData.positionId}}"
custom-style="{{getCustomStyle.videoStyle}}"
></vad-video>
<image
class="big-pic-style"
else
src="{{adData.imageUrls[0]}}"
></image>
</div>
<div style="height: 125px; align-items: center">
<vad-ad
position-id="{{adData.positionId}}"
custom-style="{{getCustomStyle.adStyle}}"
></vad-ad>
<div style="align-items: center">
<vad-button
if="{{option.isApp}}"
position-id="{{adData.positionId}}"
custom-style="{{getCustomStyle.buttonStyle}}"
></vad-button>
<div id="close-icon-target"></div>
</div>
</div>
<div style="flex-direction: column">
<vad-compliance
position-id="{{adData.positionId}}"
grid="{{getComplianceGrid}}"
custom-style="{{getCustomStyle.complianceStyle}}"
@command-click="onCommandClick"
></vad-compliance>
<vad-score
if="{{option.isApp}}"
position-id="{{adData.positionId}}"
></vad-score>
</div>
</block>
<block elif="{{renderMode === 'group-pic'}}">
<div class="show-content">
<div
if="{{adData.materialMode === 'MODE_GROUP' && adData.imageUrls}}"
>
<div style="border-radius: 40px">
<image
class="group-img"
for="(index, item) in adData.imageUrls"
src="{{item}}"
tid="{{index}}"
style="{{getImgMargin(index)}}"
></image>
</div>
</div>
<div style="width: 1000px; height: 245px" else>
<text>素材资源不符合组图要求,请检查</text>
</div>
</div>
<div style="height: 125px; align-items: center">
<vad-ad
position-id="{{adData.positionId}}"
custom-style="{{getCustomStyle.adStyle}}"
></vad-ad>
<div style="align-items: center">
<vad-button
if="{{option.isApp}}"
position-id="{{adData.positionId}}"
custom-style="{{getCustomStyle.buttonStyle}}"
></vad-button>
</div>
</div>
<div style="flex-direction: column">
<vad-compliance
position-id="{{adData.positionId}}"
grid="{{getComplianceGrid}}"
custom-style="{{getCustomStyle.complianceStyle}}"
@command-click="onCommandClick"
></vad-compliance>
<vad-score
if="{{option.isApp}}"
position-id="{{adData.positionId}}"
></vad-score>
</div>
</block>
<block elif="{{renderMode === 'left-pic-right-text'}}">
<div>
<div class="show-content">
<image class="show-image" src="{{adData.imageUrls[0]}}"></image>
</div>
<div style="flex-direction: column; width: 628px; flex: 1">
<text style="{{getCustomStyle.titleStyle}}">{{
adData.title
}}</text>
<vad-compliance
position-id="{{adData.positionId}}"
grid="{{getComplianceGrid}}"
custom-style="{{getCustomStyle.complianceStyle}}"
@command-click="onCommandClick"
></vad-compliance>
<vad-score
if="{{option.isApp}}"
position-id="{{adData.positionId}}"
></vad-score>
</div>
</div>
<div style="height: 125px; align-items: center">
<vad-ad
position-id="{{adData.positionId}}"
custom-style="{{getCustomStyle.adStyle}}"
></vad-ad>
<div style="align-items: center">
<vad-button
if="{{option.isApp}}"
position-id="{{adData.positionId}}"
custom-style="{{getCustomStyle.buttonStyle}}"
></vad-button>
</div>
</div>
</block>
<block elif="{{renderMode === 'left-text-right-pic'}}">
<div style="justify-content: space-between">
<div style="flex-direction: column; width: 628px; flex: 1">
<text style="{{getCustomStyle.titleStyle}}">{{
adData.title
}}</text>
<vad-compliance
position-id="{{adData.positionId}}"
grid="{{getComplianceGrid}}"
custom-style="{{getCustomStyle.complianceStyle}}"
@command-click="onCommandClick"
></vad-compliance>
<vad-score
if="{{option.isApp}}"
position-id="{{adData.positionId}}"
></vad-score>
</div>
<div class="show-content">
<image class="show-image" src="{{adData.imageUrls[0]}}"></image>
</div>
</div>
<div style="height: 125px; align-items: center">
<vad-ad
position-id="{{adData.positionId}}"
custom-style="{{getCustomStyle.adStyle}}"
></vad-ad>
<div style="align-items: center">
<vad-button
if="{{option.isApp}}"
position-id="{{adData.positionId}}"
custom-style="{{getCustomStyle.buttonStyle}}"
></vad-button>
</div>
</div>
</block>
<block elif="{{renderMode === 'top-pic-bottom-text'}}">
<!-- 上图下文 -->
<div class="show-content">
<vad-video
if="{{ adData.materialMode === 'MODE_VIDEO'}}"
id="vadVideo"
position-id="{{adData.positionId}}"
custom-style="{{getCustomStyle.videoStyle}}"
></vad-video>
<image class="show-image" else src="{{adData.imageUrls[0]}}"></image>
</div>
<div style="height: 125px; align-items: center">
<vad-ad
position-id="{{adData.positionId}}"
custom-style="{{getCustomStyle.adStyle}}"
></vad-ad>
<div style="align-items: center">
<vad-button
if="{{option.isApp}}"
position-id="{{adData.positionId}}"
custom-style="{{getCustomStyle.buttonStyle}}"
></vad-button>
</div>
</div>
<div style="flex-direction: column">
<text style="{{getCustomStyle.titleStyle}}">{{ adData.title }}</text>
<vad-compliance
position-id="{{adData.positionId}}"
grid="{{getComplianceGrid}}"
custom-style="{{getCustomStyle.complianceStyle}}"
@command-click="onCommandClick"
></vad-compliance>
<vad-score
if="{{option.isApp}}"
position-id="{{adData.positionId}}"
></vad-score>
</div>
</block>
<block elif="{{renderMode === 'top-text-bottom-pic'}}">
<div style="flex-direction: column">
<text style="{{getCustomStyle.titleStyle}}">{{ adData.title }}</text>
<vad-compliance
position-id="{{adData.positionId}}"
grid="{{getComplianceGrid}}"
custom-style="{{getCustomStyle.complianceStyle}}"
@command-click="onCommandClick"
></vad-compliance>
<vad-score
if="{{option.isApp}}"
position-id="{{adData.positionId}}"
></vad-score>
</div>
<div style="height: 125px; align-items: center">
<vad-ad
position-id="{{adData.positionId}}"
custom-style="{{getCustomStyle.adStyle}}"
></vad-ad>
<div style="align-items: center">
<vad-button
if="{{option.isApp}}"
position-id="{{adData.positionId}}"
custom-style="{{getCustomStyle.buttonStyle}}"
></vad-button>
</div>
</div>
<div class="show-content">
<vad-video
if="{{ adData.materialMode === 'MODE_VIDEO'}}"
id="vadVideo"
position-id="{{adData.positionId}}"
custom-style="{{getCustomStyle.videoStyle}}"
></vad-video>
<image else class="show-image" src="{{adData.imageUrls[0]}}"></image>
</div>
</block>
<!--vad-drawer-compliance 放到最低-->
<vad-drawer-compliance
visible="{{option.drawerVisible}}"
position-id="{{adData.positionId}}"
content-type="{{option.contentType}}"
@visible-change="onDrawerVisibleChange"
@tab-active="onTabActive"
></vad-drawer-compliance>
</vad-frame-feed>
</div>
</template>
<script>
import { styleObj } from "./FeedCompositeConfig.js"
export default {
props: {
positionId: {
type: String,
required: true
},
mediaId: {
type: String,
required: true
},
isRender: {
type: Boolean,
required: true,
default: false
},
templateBigHorizontal: {
type: String,
default: "top-pic-bottom-text"
},
templateBigVertical: {
type: String,
default: "big-pic"
},
templateSmall: {
type: String,
default: "left-pic-right-text"
},
templateGroup: {
type: String,
default: "group-pic"
}
},
computed: {
renderMode() {
const adDataLength = Object.keys(this.adData).length;
if (adDataLength > 0) {
return this.customMode();
} else {
return "";
}
},
containerClassName() {
const className = this.getContainerClassName(this.renderMode);
return className;
},
getComplianceGrid() {
let grid = styleObj[this.renderMode].grid;
return grid;
},
getCustomStyle() {
const videoStyle = styleObj[this.renderMode];
const customStyle = {
buttonStyle: {},
complianceStyle: {
containerStyle: {},
itemStyle: {
paddingLeft: 0,
color: "#999999"
},
separatorStyle: {
display: "none"
},
groupStyle: {}
},
appNameStyle: {
color: "#f6642c"
},
titleStyle: {
color: "#000",
fontSize: "48px",
fontStyle: "normal",
fontWeight: 400,
lineHeight: "60px",
lines: 2,
textOverflow: "ellipsis",
},
adStyle: {
containerStyle: {
borderRadius: "14px",
backgroundColor: "#dddddd"
}
}
};
Object.assign(customStyle, videoStyle);
return customStyle;
}
},
// 页面级组件的数据模型,影响传入数据的覆盖机制:private内定义的属性不允许被覆盖
data() {
return {
option: {
contentType: '',
drawerVisible: false,
closePosition: {
top: 20,
right: 20
},
isDonwloadApp: false,
isApp: false,
materialMode: ''
},
adData: {},
adDataStr: '',
testShow: false
}
},
getContainerClassName(mode) {
let className;
switch (mode) {
case "big-pic":
className = "feed-big-pic-container";
break;
case "group-pic":
className = "feed-group-pic-container";
break;
case "left-pic-right-text":
className = "feed-left-pic-right-text-container";
break;
case "left-text-right-pic":
className = "feed-left-text-right-pic-container";
break;
case "top-pic-bottom-text":
className = "feed-top-pic-bottom-text-container";
break;
case "top-text-bottom-pic":
className = "feed-top-text-bottom-pic-container";
break;
default:
className = "";
break;
}
return className;
},
/**
* 此部分为自定义逻辑,将根据返回的素材自动决定展示模板
* 因为模板素材较多,所以该示例仅展示部分模板
*/
customMode() {
/**
* "MODE_VIDEO" 视频模式
* "MODE_GROUP" 组图模式
* "MODE_LARGE" 大图模式
* "MODE_SMALL" 小图模式
*/
const materialMode = this.adData.materialMode;
const width = this.adData.dimensions[0];
const height = this.adData.dimensions[1];
switch (materialMode) {
case "MODE_VIDEO":
return this.templateBigHorizontal;
break;
case "MODE_GROUP":
return this.templateGroup;
break;
case "MODE_LARGE":
return width > height ? this.templateBigHorizontal : this.templateBigVertical;
break;
case "MODE_SMALL":
return this.templateSmall;
break;
default:
break;
}
return mode;
},
onCommandClick(evt) {
this.option.drawerVisible = true;
this.option.contentType = evt.detail
},
onTabActive(evt) {
this.option.contentType = evt.detail;
},
onFeedAdLoad(evt) {
this.adData = evt.detail.adData;
this.option.isApp = this.isApp(this.adData.app);
},
isApp(app) {
return !!app;
},
// 关联vad-video组件,视频播放与暂停
onDrawerVisibleChange(evt) {
this.option.drawerVisible = evt.detail;
},
getImgMargin(index) {
if (index === 0) {
return {
"marginRight": "4.5px"
}
} else if (index === 1) {
return {
"marginLeft": "4.5px",
"marginRight": "4.5px"
}
} else if (index === 2) {
return {
"marginLeft": "4.5px"
}
}
}
}
</script>
<style>
@import './FeedComposite.css';
</style>
CSS文件:FeedComposite.css
css
/* 大图模板样式 --- 开始 */
.feed-big-pic-container {
flex-direction: column;
width: 1000px;
margin-top: 20px;
margin-left: auto;
margin-right: auto;
}
.feed-big-pic-container .show-content {
width: 100%;
}
.feed-big-pic-container .show-content .big-pic-style {
width: 1000px;
height: 1778px;
object-fit: fill;
background-color: #dddddd;
border-radius: 40px;
}
/* 大图模板样式 --- 结束 */
/* 组图模板样式 --- 开始 */
.feed-group-pic-container {
flex-direction: column;
width: 1000px;
margin-top: 20px;
margin-left: auto;
margin-right: auto;
}
.feed-group-pic-container .show-content {
width: 100%;
}
.feed-group-pic-container .show-content .group-img {
width: 327px;
height: 245px;
object-fit: contain;
border-radius: 40px;
}
/* 组图模板样式 --- 结束 */
/* 左图右文模板样式 --- 开始 */
.feed-left-pic-right-text-container {
flex-direction: column;
margin-left: auto;
margin-right: auto;
width: 1000px;
}
.feed-left-pic-right-text-container .show-content {
border-radius: 40px;
height: 246px;
background-color: #dddddd;
margin-right: 40px;
flex-grow: 0;
}
.feed-left-pic-right-text-container .show-content .show-image {
object-fit: contain;
}
/* 左图右文模板样式 --- 结束 */
/* 左文右图模板样式 --- 开始 */
.feed-left-text-right-pic-container {
flex-direction: column;
margin-left: auto;
margin-right: auto;
width: 1000px;
}
.feed-left-text-right-pic-container .show-content {
border-radius: 40px;
height: 246px;
background-color: #dddddd;
margin-left: 73px;
flex-grow: 0;
}
.feed-left-text-right-pic-container .show-content .show-image {
object-fit: contain;
}
/* 左文右图模板样式 --- 结束 */
/* 上图下文模板样式 --- 开始 */
.feed-top-pic-bottom-text-container {
flex-direction: column;
margin-left: auto;
margin-right: auto;
width: 1000px;
}
.feed-top-pic-bottom-text-container .show-content {
border-radius: 40px;
height: 562.5px;
background-color: #dddddd;
}
.feed-top-pic-bottom-text-container .show-content .show-image {
object-fit: contain;
}
/* 上图下文模板样式 --- 结束 */
/* 上文下图模板样式 --- 开始 */
.feed-top-text-bottom-pic-container {
flex-direction: column;
width: 1000px;
margin-left: auto;
margin-right: auto;
}
.feed-top-text-bottom-pic-container .show-content {
border-radius: 40px;
height: 562.5px;
background-color: #dddddd;
}
.feed-top-text-bottom-pic-container .show-content .show-image {
object-fit: contain;
}
/* 上文下图模板样式 --- 结束 */
JS文件:FeedCompositeConfig.js
js
export const styleObj = {
"big-pic": {
grid: [[1, 2], [3, 4, 5, 6]],
videoStyle: {
containerStyle: {
width: '1000px',
height: '1778px',
borderRadius: '40px',
overflow: 'hidden',
},
videoStyle: {
width: '1000px',
height: '1778px',
objectFit: 'contain',
},
maskStyle: {
width: '1000px',
height: '1778px',
},
},
},
"group-pic": {
grid: [[1,2], [3], [4,5,6]]
},
"left-pic-right-text": {
grid: [[1,2], [3], [4,5,6]]
},
"left-text-right-pic": {
grid: [[1,2], [3], [4,5,6]]
},
"top-pic-bottom-text": {
grid: [[1,2,4,5,6],[3]],
videoStyle: {
containerStyle: {
width: '1000px',
height: '563px',
borderRadius: '40px',
overflow: 'hidden',
},
videoStyle: {
width: '1000px',
height: '563px',
objectFit: 'contain',
},
maskStyle: {
width: '1000px',
height: '563px',
},
},
},
"top-text-bottom-pic": {
grid: [[1,2,4,5,6],[3]],
videoStyle: {
containerStyle: {
width: '1000px',
height: '563px',
borderRadius: '40px',
overflow: 'hidden',
},
videoStyle: {
width: '1000px',
height: '563px',
objectFit: 'contain',
},
maskStyle: {
width: '1000px',
height: '563px',
},
},
},
}
2.3 属性说明
属性名 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
position-id | string | none | 是 | 广告位id |
media-id | string | none | 是 | 媒体id |
is-render | boolean | false | 是 | 是否展示广告 |
template-big-horizontal | string | top-pic-bottom-text | 否 | 大图横屏模板: ①.top-pic-bottom-text ②.top-text-bottom-pic |
template-big-vertical | string | big-pic | 否 | 大图竖屏模板: ①.big-pic |
template-small | string | left-pic-right-text | 否 | 小图模板: ①.left-pic-right-text ②.left-text-right-pic |
template-group | string | group-pic | 否 | 组图模板: ①.group-pic |
@ad-load | event | none | 是 | 广告加载触发事件 onAdLoad(evt: MouseEvent):void{}
|
@ad-error | event | none | 否 | 广告异常触发事件 |