ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# component自定义组件目录 自定义页面是由组件进行配置开发的,自定义组件开发包括后台配置与uniapp页面展示,下面说明后台配置方面,具体的自定义模板开发会在模板开发详细说明 ## component目录 ``` ├─component ├─├─controller │ Article.php 文章组件 │ BaseDiyView.php 自定义组件基类 │ FloatBtn.php 浮动按钮 │ GoodsBrand.php 商品品牌 │ GoodsCategory.php 商品分类 │ GoodsList.php 商品列表 │ GoodsRecommend.php 商品推荐 │ HorzBlank.php 辅助空白 │ HorzLine.php 辅助线 │ ImageAds.php 图片广告 │ ManyGoodsList.php 多商品组 │ Notice.php 公告 │ RichText.php 富文本 │ RubikCube.php 魔方 │ Search.php 商品搜索 │ Text.php 标题 │ TopCategory.php 顶部商品分类 │ Video.php 视频 ``` **一,设计自定义组件后台配置** ~~~ <?php namespace app\component\controller; /** * 公告·组件 */ class Notice extends BaseDiyView { /** * 后台编辑界面 */ public function design() { return $this->fetch("notice/design.html"); } } ~~~ ~~~ <nc-component :data="data[index]" class="notice"> <!-- 预览 --> <template slot="preview"> <template v-if="nc.lazyLoad"> <div class="preview-box" :style="{ borderTopLeftRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0), borderTopRightRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0), borderBottomLeftRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0), borderBottomRightRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0), backgroundColor : nc.componentBgColor }"> <div :class="['notice-box',nc.contentStyle]"> <div class="notice-con" v-for="(item, previewIndex) in nc.list" v-if="previewIndex < 1"> <div :class="['img-wrap',nc.iconType]" v-if="previewIndex == 0"> <img v-if="nc.iconType == 'img'" :src="changeImgUrl(nc.imageUrl)" /> <div v-if="nc.iconType == 'icon'" class="icon-box"> <iconfont :icon="nc.icon" v-if="nc.icon" :value="nc.style ? nc.style : ''"></iconfont> </div> </div> <div class="notice-con-split"></div> <span v-if="nc.contentStyle=='style-2'" class="iconfont icongonggao notice-icon-one" :style="{color: nc.textColor ? nc.textColor : 'rgba(0,0,0,0)'}"></span> <span class="notice-con-font" :style="{color: nc.textColor ? nc.textColor : 'rgba(0,0,0,0)'}">{{ item.title }}</span> <span v-if="nc.contentStyle=='style-2'" class="iconfont iconyoujiantou notice-icon-two"></span> </div> </div> </div> </template> </template> <!-- 内容编辑 --> <template slot="edit-content"> <template v-if="nc.lazyLoad"> <notice-sources></notice-sources> <div class="template-edit-title"> <h3>公告风格</h3> <div class="goods-list-edit layui-form" v-if="nc.tempData.iconList"> <div class="layui-form-item icon-radio"> <label class="layui-form-label sm">公告图标</label> <div class="layui-input-block"> <span v-for="(item, sourcesKey) in nc.tempData.iconList" :key="sourcesKey" :class="[sourcesKey == nc.iconSources ? '' : 'layui-hide']">{{item.text}}</span> <ul class="icon-wrap"> <li v-for="(item, sourcesKey) in nc.tempData.iconList" :key="sourcesKey" :class="[sourcesKey == nc.iconSources ? 'text-color border-color' : '']" @click="nc.iconSources=sourcesKey;nc.iconType=item.type;"> <i class="iconfont" :class="[{'text-color': sourcesKey == nc.iconSources}, item.src]"></i> </li> </ul> </div> <div v-if="nc.iconSources == 'initial'" class="system-img"> <div class="system-img-item" v-for="item in nc.tempData.iconList[nc.iconSources].icon" :class="{'border-color': nc.imageUrl == item}" @click="nc.imageUrl = item"> <img :src="item"/> </div> </div> </div> <div class="diy-img" v-show="nc.iconSources == 'diy'"> <img-icon-upload :data="{data : nc}"></img-icon-upload> <div class="right-wrap"> <div class="action-box" v-show="nc.iconType == 'icon'"> <div class="action" @click="nc.tempData.methods.iconStyle($event)"><i class="iconfont iconpifu"></i></div> <div class="action" :id="'notice-color-' + nc.index"><i class="iconfont iconyanse"></i></div> </div> <div class="desc">高度20像素,宽度自适应</div> </div> </div> <div class="layui-form-item"> <label class="layui-form-label sm">风格</label> <div class="layui-input-block"> <div @click="nc.contentStyle='style-1'" :class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.contentStyle=='style-1') }"> <i class="layui-anim layui-icon">{{ nc.contentStyle=='style-1' ? "&#xe643;" : "&#xe63f;" }}</i> <div>风格一</div> </div> <div @click="nc.contentStyle='style-2'" :class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.contentStyle=='style-2') }"> <i class="layui-anim layui-icon">{{ nc.contentStyle=='style-2' ? "&#xe643;" : "&#xe63f;" }}</i> <div>风格二</div> </div> </div> </div> </div> </div> <div class="template-edit-title"> <h3>公告内容</h3> <div class="layui-form-item" v-if="nc.tempData.noticeSources"> <label class="layui-form-label sm">数据来源</label> <div class="layui-input-block"> <div class="source-selected"> <div class="source">{{ nc.tempData.noticeSources[nc.sources].text }}</div> <div v-for="(item,sourcesKey) in nc.tempData.noticeSources" :key="sourcesKey" class="source-item" :title="item.text" @click="nc.sources=sourcesKey" :class="{ 'text-color border-color' : (nc.sources == sourcesKey) }"> <i class='iconfont' :class='item.icon'></i> </div> </div> </div> </div> <div class="layui-form-item" v-if="nc.sources == 'initial' && nc.tempData.methods"> <label class="layui-form-label sm">选择公告</label> <div class="layui-input-block"> <div class="input-text selected-style" @click="nc.tempData.methods.addNotice()"> <span v-if="nc.noticeIds.length == 0">请选择</span> <span v-if="nc.noticeIds.length > 0" class="text-color">已选{{ nc.noticeIds.length }}个</span> <i class="iconfont iconyoujiantou"></i> </div> </div> </div> <div class="notice-config" v-if="nc.sources == 'diy'"> <ul> <li v-for="(item,index) in nc.list"> <div class="content-block"> <div class="layui-form-item" > <label class="layui-form-label sm">公告内容</label> <div class="layui-input-block"> <input type="text" name='title' v-model="item.title" class="layui-input" /> </div> </div> <nc-link :data="{ field : nc.list[index].link }"></nc-link> </div> <i class="del" @click="list.splice(index,1)">x</i> </li> </ul> <div class="add-item text-color border-color" @click="nc.list.push({ title:'公告',link:{name:''}})"> <i>+</i> <span>添加一条公告</span> </div> </div> </div> </template> </template> <!-- 样式编辑 --> <template slot="edit-style"> <template v-if="nc.lazyLoad"> <div class="template-edit-title"> <h3>公告样式</h3> <color :data="{ field : 'textColor', 'label' : '文本颜色','defaultColor': '#303133' }"></color> </div> </template> </template> <!-- 资源 --> <template slot="resource"> <js> var noticeResourcePath = "{$resource_path}"; </js> <css src="{$resource_path}/css/design.css"></css> <js src="{$resource_path}/js/design.js"></js> </template> </nc-component> ~~~ **一,uniapp开发** 自定义组件统计在components/diy-components ~~~ <template> <view class="diy-notice"> <view class="notice notice-1" :style="noticeWrapCss"> <image v-if="value.iconType == 'img'" class="notice-img" :src="$util.img(value.imageUrl)" mode="heightFix"></image> <diy-icon v-if="value.iconType == 'icon'" :icon="value.icon" :value="value.style ? value.style : 'null'" :style="{ maxWidth: 30 * 2 + 'rpx', maxHeight: 30 * 2 + 'rpx', width: '100%', height: '100%' }" ></diy-icon> <view class="notice-xian"></view> <view class="main-wrap"> <view class="uni-swiper-msg"> <swiper vertical="true" autoplay="true" duration="0" circular="true"> <swiper-item v-for="(item, index) in list" :key="index" @touchmove.stop> <text @click="toLink(item)" class="beyond-hiding animate" :style="{ color: value.textColor }">{{ item.title }}</text> </swiper-item> </swiper> </view> </view> </view> </view> </template> <script> // 公告 export default { name: 'diy-notice', props: { value: { type: Object } }, data() { return { list: [] }; }, computed: { noticeWrapCss: function() { var obj = ''; obj += 'background-color:' + this.value.componentBgColor + ';'; if (this.value.componentAngle == 'round') { obj += 'border-top-left-radius:' + this.value.topAroundRadius * 2 + 'rpx;'; obj += 'border-top-right-radius:' + this.value.topAroundRadius * 2 + 'rpx;'; obj += 'border-bottom-left-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;'; obj += 'border-bottom-right-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;'; } return obj; } }, created() { // 数据源:公告系统 if (this.value.sources == 'default') this.getData(); else this.list = this.value.list; }, methods: { getData() { var data = {}; data.id_arr = this.value.noticeIds.toString(); this.$api.sendRequest({ url: '/api/notice/lists', data: data, success: res => { if (res.code == 0 && res.data) { this.list = res.data; console.log('test - 公告信息', this.list); } } }); }, toLink(item) { if (this.value.sources == 'default') this.$util.redirectTo('/pages_tool/notice/detail', { notice_id: item.id }); else this.$util.diyRedirectTo(item.link); } } }; </script> <style lang="scss"> .notice-1 { height: 80rpx; position: relative; display: flex; align-items: center; overflow: hidden; padding: 20rpx; font-size: 70rpx; .notice-img { width: 212rpx; height: 40rpx; } .notice-xian { width: 1rpx; height: 26rpx; background-color: #e4e4e4; margin: 0 22rpx; } } .main-wrap { display: inline-block; width: calc(100% - 115rpx); position: relative; } swiper { height: 50rpx; } .beyond-hiding { display: inline-block; width: 100%; white-space: nowrap; } .animate { padding-left: 40rpx; font-size: $font-size-base; color: #000; display: inline-block; white-space: nowrap; animation: 5s wordsLoop linear infinite normal; } @keyframes wordsLoop { 0% { transform: translateX(400rpx); -webkit-transform: translateX(400rpx); } 100% { transform: translateX(-100%); -webkit-transform: translateX(-100%); } } @-webkit-keyframes wordsLoop { 0% { transform: translateX(400rpx); -webkit-transform: translateX(400rpx); } 100% { transform: translateX(-100%); -webkit-transform: translateX(-100%); } } </style> ~~~