Commit 4e4e1a32 by Hao

Initial commit

parents
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
node: true,
},
extends: [
"eslint:recommended",
"plugin:vue/essential",
"plugin:prettier/recommended",
],
parserOptions: {
ecmaVersion: 12,
sourceType: "module",
parser: "babel-eslint",
},
plugins: ["vue", "prettier"],
rules: {
"no-console": "off",
"no-unused-vars": [
"warn",
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
],
"prettier/prettier": "error",
},
settings: {
"import/resolver": {
node: {
extensions: [".js", ".jsx", ".vue"],
},
},
},
};
# Dependencies
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
# Build outputs
dist
build
*.tsbuildinfo
# Environment variables
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Dependency directories
jspm_packages/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# parcel-bundler cache
.cache
.parcel-cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
.cache
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
# Dependencies
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
# Build outputs
dist
build
*.tsbuildinfo
# Environment variables
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Dependency directories
jspm_packages/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# parcel-bundler cache
.cache
.parcel-cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
.cache
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
\ No newline at end of file
1.常用的浏览器内核有哪些
webkit(苹果,早期的 Chrome,早期的 Opera),Blink(谷歌,欧朋,新版 Edge),Gecko(火狐浏览器),Trident,EdgeHTML 2.行类元素和块级元素的区别
行类元素:不独占一行,宽度自适应内容宽度,只能包含行类元素或文本节点
块级元素:独占一行,宽度默认 100%,可以包含行类元素或块级元素 3.清除浮动的方法有哪些
清除浮动的方法有以下几种: 1.使用 clearfix 类名 2.使用伪元素清除浮动 3.使用 overflow 属性清除浮动 4.使用 display 属性清除浮动 5.使用 float 属性清除浮动 4.如何理解 javascript 中 this 1.在全局执行环境中,this 指向 window 对象 2.在函数中,this 指向调用该函数的当前对象 3.在对象的方法中,this 指向该对象的实例 4.在构造函数中,this 指向新创建的对象实例 4.在箭头函数中,this 指向定义时的上下文环境 5.在事件处理函数中,this 指向触发事件的 DOM 元素 6.在 bind 方法中,this 指向 bind 方法的第一个参数 7.在 call 和 apply 方法中,this 指向 call 和 apply 方法的第一个参数 8.在 Promise 的回调函数中,this 指向 undefined 9.在 Generator 函数中,this 指向 Generator 函数的实例 10.在 async 函数中,this 指向 async 函数的实例 5.原始类型和引用类型有什么区别
原始类型:number,string,boolean,null,undefined,symbol,bigint
引用类型:object,function,Array,Date,RegExp,Error,Map,Set,WeakMap,WeakSet 6.如何深拷贝一个对象 7.数组去重的方法有哪些 8.同步和异步的区别
9.get 和 post 请求的区别 10.跨域请求有哪些方案
1.jsonp (只支持 get 请求)
2.cors (跨域资源共享) 3.反向代理 (服务器端配置)
4.websocket (全双工通信协议)
5.postMessage (html5 新特性)
1.常用的浏览器内核有哪些
webkit , blink ,gecko,trident 2.行类元素和块级元素的区别
3.清除浮动的方法有哪些
4.如何理解 javascript 中 this
5.原始类型和引用类型有什么区别
6.如何深拷贝一个对象 7.数组去重的方法有哪些 8.同步和异步的区别
9.get 和 post 请求的区别 10.跨域请求有哪些方案
11.new 的过程做了哪些操作
MIT License
Copyright (c) [year] [your name]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
\ No newline at end of file
基本数据类型
string
Number
Boolean
undefined
null
Symbol
BigInt
引用数据类型
Object
Array
Function
Date
RegExp
Set
Map
基本数据类型和引用数据类型的区别
基本数据类型存储在栈内存中,引用数据类型存储在堆内存中,栈内存中存储的是引用数据类型的地址
基本数据类型和引用数据类型的赋值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport =
"CSS" in window &&
typeof CSS.supports === "function" &&
(CSS.supports("top: env(a)") || CSS.supports("top: constant(a)"));
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ", viewport-fit=cover" : "") +
'" />'
);
</script>
<title></title>
<style>
#app {
width: 750px;
margin: 0 auto;
border: 1px dotted #a4a2a2;
}
</style>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
{
"name": "uni-preset-vue",
"version": "0.0.0",
"scripts": {
"dev": "uni build --outDir ../win/public/app",
"serve": "uni build --outDir ../../public/app",
"dev:app": "uni -p app",
"dev:custom": "uni -p",
"dev:h5": "uni",
"dev:h5:ssr": "uni --ssr",
"dev:mp-alipay": "uni -p mp-alipay",
"dev:mp-baidu": "uni -p mp-baidu",
"dev:mp-kuaishou": "uni -p mp-kuaishou",
"dev:mp-lark": "uni -p mp-lark",
"dev:mp-qq": "uni -p mp-qq",
"dev:mp-toutiao": "uni -p mp-toutiao",
"dev:mp-weixin": "uni -p mp-weixin",
"dev:quickapp-webview": "uni -p quickapp-webview",
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
"build:app": "uni build -p app",
"build:custom": "uni build -p",
"build:h5": "uni build",
"build:h5:ssr": "uni build --ssr",
"build:mp-alipay": "uni build -p mp-alipay",
"build:mp-baidu": "uni build -p mp-baidu",
"build:mp-kuaishou": "uni build -p mp-kuaishou",
"build:mp-lark": "uni build -p mp-lark",
"build:mp-qq": "uni build -p mp-qq",
"build:mp-toutiao": "uni build -p mp-toutiao",
"build:mp-weixin": "uni build -p mp-weixin",
"build:quickapp-webview": "uni build -p quickapp-webview",
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
"build:quickapp-webview-union": "uni build -p quickapp-webview-union"
},
"dependencies": {
"@dcloudio/uni-app": "3.0.0-alpha-3040620220419003",
"@dcloudio/uni-app-plus": "3.0.0-alpha-3040620220419003",
"@dcloudio/uni-components": "3.0.0-alpha-3040620220419003",
"@dcloudio/uni-h5": "3.0.0-alpha-3040620220419003",
"@dcloudio/uni-mp-alipay": "3.0.0-alpha-3040620220419003",
"@dcloudio/uni-mp-baidu": "3.0.0-alpha-3040620220419003",
"@dcloudio/uni-mp-kuaishou": "3.0.0-alpha-3040620220419003",
"@dcloudio/uni-mp-lark": "3.0.0-alpha-3040620220419003",
"@dcloudio/uni-mp-qq": "3.0.0-alpha-3040620220419003",
"@dcloudio/uni-mp-toutiao": "3.0.0-alpha-3040620220419003",
"@dcloudio/uni-mp-weixin": "3.0.0-alpha-3040620220419003",
"@dcloudio/uni-quickapp-webview": "3.0.0-alpha-3040620220419003",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"node-sass": "^7.0.1",
"sass-loader": "^12.6.0",
"vue": "^3.2.33",
"vue-i18n": "^9.1.9",
"vuex": "^4.0.2"
},
"devDependencies": {
"@dcloudio/types": "^2.5.17",
"@dcloudio/uni-automator": "3.0.0-alpha-3040620220419003",
"@dcloudio/uni-cli-shared": "3.0.0-alpha-3040620220419003",
"@dcloudio/vite-plugin-uni": "3.0.0-alpha-3040620220419003",
"autoprefixer": "^10.4.2",
"sass": "^1.52.0",
"vite": "^2.9.5"
}
}
<script>
export default {
onLaunch: function () {
console.log("App Launch");
},
onShow: function () {
console.log("App Show");
},
onHide: function () {
console.log("App Hide");
},
};
</script>
<style lang="less">
#app {
width: 375px;
border: 0;
background: #f5f5f5;
overflow-y: auto;
uni-page-body {
height: 100%;
}
}
@import "~@/components/shop-decorater/index.less";
</style>
/*
解析和匹配 Css 的选择器
github:https://github.com/jin-yufeng/Parser
docs:https://jin-yufeng.github.io/Parser
author:JinYufeng
update:2020/03/15
*/
import cfg from "./config.js";
class CssHandler {
constructor(tagStyle) {
var styles = Object.assign({}, cfg.userAgentStyles);
for (var item in tagStyle)
styles[item] = (styles[item] ? styles[item] + ";" : "") + tagStyle[item];
this.styles = styles;
}
getStyle = (data) => (this.styles = new CssParser(data, this.styles).parse());
match(name, attrs) {
var tmp,
matched = (tmp = this.styles[name]) ? tmp + ";" : "";
if (attrs.class) {
var items = attrs.class.split(" ");
for (var i = 0, item; (item = items[i]); i++)
if ((tmp = this.styles["." + item])) matched += tmp + ";";
}
if ((tmp = this.styles["#" + attrs.id])) matched += tmp + ";";
return matched;
}
}
class CssParser {
constructor(data, init) {
this.data = data;
this.floor = 0;
this.i = 0;
this.list = [];
this.res = init;
this.state = this.Space;
}
parse() {
for (var c; (c = this.data[this.i]); this.i++) this.state(c);
return this.res;
}
section = () => this.data.substring(this.start, this.i);
isLetter = (c) => (c >= "a" && c <= "z") || (c >= "A" && c <= "Z");
// 状态机
Space(c) {
if (c == "." || c == "#" || this.isLetter(c)) {
this.start = this.i;
this.state = this.Name;
} else if (c == "/" && this.data[this.i + 1] == "*") this.Comment();
else if (!cfg.blankChar[c] && c != ";") this.state = this.Ignore;
}
Comment() {
this.i = this.data.indexOf("*/", this.i) + 1;
if (!this.i) this.i = this.data.length;
this.state = this.Space;
}
Ignore(c) {
if (c == "{") this.floor++;
else if (c == "}" && !--this.floor) this.state = this.Space;
}
Name(c) {
if (cfg.blankChar[c]) {
this.list.push(this.section());
this.state = this.NameSpace;
} else if (c == "{") {
this.list.push(this.section());
this.Content();
} else if (c == ",") {
this.list.push(this.section());
this.Comma();
} else if (
!this.isLetter(c) &&
(c < "0" || c > "9") &&
c != "-" &&
c != "_"
)
this.state = this.Ignore;
}
NameSpace(c) {
if (c == "{") this.Content();
else if (c == ",") this.Comma();
else if (!cfg.blankChar[c]) this.state = this.Ignore;
}
Comma() {
while (cfg.blankChar[this.data[++this.i]]);
if (this.data[this.i] == "{") this.Content();
else {
this.start = this.i--;
this.state = this.Name;
}
}
Content() {
this.start = ++this.i;
if ((this.i = this.data.indexOf("}", this.i)) == -1)
this.i = this.data.length;
var content = this.section();
for (var i = 0, item; (item = this.list[i++]); )
if (this.res[item]) this.res[item] += ";" + content;
else this.res[item] = content;
this.list = [];
this.state = this.Space;
}
}
export default CssHandler;
/* 配置文件 */
// #ifdef MP-WEIXIN
const canIUse = wx.canIUse("editor"); // 高基础库标识,用于兼容
// #endif
function makeMap(str) {
var map = {},
list = str.split(",");
for (var i = list.length; i--; ) map[list[i]] = true;
return map;
}
export default {
// 过滤器函数
filter: null,
// 代码高亮函数
highlight: null,
// 文本处理函数
onText: null,
// 实体编码列表
entities: {
quot: '"',
apos: "'",
semi: ";",
nbsp: "\xA0",
ensp: "\u2002",
emsp: "\u2003",
ndash: "–",
mdash: "—",
middot: "·",
lsquo: "‘",
rsquo: "’",
ldquo: "“",
rdquo: "”",
bull: "•",
hellip: "…",
},
blankChar: makeMap(" ,\xA0,\t,\r,\n,\f"),
// 块级标签,将被转为 div
blockTags: (function (makeMap) {
let str =
"address,article,aside,body,caption,center,cite,footer,header,html,nav,section";
// #ifdef MP-WEIXIN
str = str + (canIUse ? "" : ",pre");
// #endif
// #ifndef MP-WEIXIN
str = str + ",pre";
// #endif
return makeMap(str);
})(makeMap),
// 将被移除的标签
ignoreTags: (function (makeMap) {
let str =
"area,base,basefont,canvas,command,frame,input,isindex,keygen,link,map,meta,param,script,source,style,svg,textarea,title,track,use,wbr";
// #ifdef MP-WEIXIN
str = str + (canIUse ? ",rp" : "");
// #endif
// #ifndef APP-PLUS
str = str + ",embed,iframe";
// #endif
return makeMap(str);
})(makeMap),
// 只能被 rich-text 显示的标签
richOnlyTags: (function (makeMap) {
let str = "a,colgroup,fieldset,legend,picture,table";
// #ifdef MP-WEIXIN
str = str + (canIUse ? ",bdi,bdo,caption,rt,ruby" : "");
// #endif
return makeMap(str);
})(makeMap),
// 自闭合的标签
selfClosingTags: makeMap(
"area,base,basefont,br,col,circle,ellipse,embed,frame,hr,img,input,isindex,keygen,line,link,meta,param,path,polygon,rect,source,track,use,wbr"
),
// 信任的属性
trustAttrs: makeMap(
"align,alt,app-id,author,autoplay,border,cellpadding,cellspacing,class,color,colspan,controls,data-src,dir,face,height,href,id,ignore,loop,media,muted,name,path,poster,rowspan,size,span,src,start,style,type,unit-id,width,xmlns"
),
// bool 型的属性
boolAttrs: makeMap("autoplay,controls,ignore,loop,muted"),
// 信任的标签
trustTags: (function (makeMap) {
let str =
"a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video";
// #ifdef MP-WEIXIN
str = str + (canIUse ? ",bdi,bdo,caption,pre,rt,ruby" : "");
// #endif
// #ifdef APP-PLUS
str = str + ",embed,iframe";
// #endif
return makeMap(str);
})(makeMap),
// 默认的标签样式
userAgentStyles: {
address: "font-style:italic",
big: "display:inline;font-size:1.2em",
blockquote:
"background-color:#f6f6f6;border-left:3px solid #dbdbdb;color:#6c6c6c;padding:5px 0 5px 10px",
caption: "display:table-caption;text-align:center",
center: "text-align:center",
cite: "font-style:italic",
dd: "margin-left:40px",
mark: "background-color:yellow",
pre: "font-family:monospace;white-space:pre;overflow:scroll",
s: "text-decoration:line-through",
small: "display:inline;font-size:0.8em",
u: "text-decoration:underline",
},
};
var inlineTags = {
abbr: 1,
b: 1,
big: 1,
code: 1,
del: 1,
em: 1,
i: 1,
ins: 1,
label: 1,
q: 1,
small: 1,
span: 1,
strong: 1,
};
export default {
useRichText: function (item) {
var style = (item.attrs && item.attrs.style) || "";
return (
!item.c && !inlineTags[item.name] && style.indexOf("display:inline") == -1
);
},
};
var inlineTags = {
abbr: 1,
b: 1,
big: 1,
code: 1,
del: 1,
em: 1,
i: 1,
ins: 1,
label: 1,
q: 1,
small: 1,
span: 1,
strong: 1,
};
module.exports = {
useRichText: function (item) {
var style = (item.attrs && item.attrs.style) || "";
return (
!item.c && !inlineTags[item.name] && style.indexOf("display:inline") == -1
);
},
};
<template>
<!-- 图标[park,scan,返回] 文本[title] 搜索[search] -->
<!-- 布局:居中-左右-左中右 -->
<view class="dec-header" :style="{ height: totalHeight + 'px' }">
<view
v-if="arg.mode == 'custom'"
:class="{ fixed: arg.styleArg == 'fixed' }"
>
<view
class="header-top"
:style="{ height: statusBarHeight + 'px' }"
></view>
<view v-else class="header-bottom" @tap="showShopList" v-if="shopName">
<view class="at-name" @tap.stop="switch">
<uni-icons
v-if="arg.back"
@tap.stop="back"
type="back"
size="30"
color="#333333"
class="at-back"
></uni-icons>
{{ shopName }}
<uni-icons
v-if="arg.shop"
type="bottom"
size="14"
color="#333333"
class="at-dot"
></uni-icons>
</view>
<view class="at-scan" @tap.stop="headFn('park')">
<image
lazy-load
mode="widthFix"
src="https://lirimall.test.tikcos.cn/lirimall/jeditor/333_1658414626394.png"
/>
</view>
<view class="at-scan" @tap.stop="headFn('scan')">
<image
lazy-load
mode="widthFix"
src="https://lirimall.test.tikcos.cn/lirimall/jeditor/222_1658414610148.png"
/>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "dec-header",
props: {
arg: {
type: Object,
default() {
return {};
},
},
},
data() {
return {
totalHeight: 64,
statusBarHeight: 20,
titleBarHeight: 44,
titleBarWidth: "",
imgUrl: "https://lirimall.test.tikcos.cn/lirimall",
fnIcon: {
park: "/jeditor/333_1658414626394.png",
scan: "/jeditor/222_1658414610148.png",
},
};
},
created() {
//兼容苹果手机手机刘海屏状态栏显示不全的问题
let systemInfo = uni.getSystemInfoSync();
this.statusBarHeight = systemInfo.statusBarHeight;
// 胶囊信息-头部高度
let menuButtonInfo = uni.getMenuButtonBoundingClientRect();
const titleBarHeight =
(menuButtonInfo.top - this.statusBarHeight) * 2 + menuButtonInfo.height;
const titleBarWidth = menuButtonInfo.left;
this.titleBarHeight = titleBarHeight || 44;
this.titleBarWidth = titleBarWidth || "";
if (this.arg.mode == "custom") {
this.totalHeight = this.statusBarHeight + this.titleBarHeight;
} else {
this.totalHeight = 0;
}
this.$emit("titleBarHeight", this.titleBarHeight);
},
mounted() {
if (this.fixed) {
const query = uni.createSelectorQuery().in(this);
query
.select(".dec-header")
.boundingClientRect((data) => {
this.$emit("inited", data);
})
.exec();
}
},
methods: {
back() {
uni.navigateBack({ delta: 1 });
},
switch() {},
},
};
</script>
<style lang="scss" scoped>
.dec-header {
position: relative;
z-index: 10;
}
.fixed {
position: fixed;
width: 100%;
left: 0rpx;
top: 0rpx;
}
.header-top {
height: var(--status-bar-height);
}
.header-bottom {
display: flex;
flex-wrap: nowrap;
align-items: center;
width: 100%;
height: 88rpx;
padding: 0rpx 20rpx;
.at-name {
height: 48rpx;
width: 100%;
font-size: 40rpx;
line-height: 1.2;
color: #333333;
font-weight: bold;
margin-right: 10rpx;
@include textEllipsis(1);
}
.at-back {
margin-right: 10px;
}
.at-dot {
margin-left: 5px;
}
.at-scan {
flex-shrink: 0;
display: inline-block;
height: 64rpx;
width: 64rpx;
border-radius: 50%;
text-align: center;
margin-left: 20rpx;
background: #0000002e;
overflow: hidden;
image {
height: 46rpx;
width: 46rpx;
}
}
}
</style>
<template>
<!--下拉加载 -->
<view class="load-more-box">
<uni-load-more
:status="status"
:iconSize="20"
@clickLoadMore="clickLoadMore"
:contentText="contentText"
></uni-load-more>
</view>
</template>
<script>
export default {
props: {
status: {
type: String,
default: "noMore",
},
},
data() {
return {
contentText: {
contentdown: "上拉显示更多!",
contentrefresh: "加载中!",
contentnomore: "我也有底线~",
},
};
},
methods: {
clickLoadMore(e) {},
},
};
</script>
<style lang="scss">
.load-more-box {
padding: 20rpx 0rpx;
.uni-load-more__text {
font-size: 26rpx;
}
}
</style>
<template>
<view class="loading">
<view class="load">
<view class="loader"></view>
</view>
</view>
</template>
<script>
export default {
name: "fileLoading",
data() {
return {};
},
};
</script>
<style lang="less">
.loading {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: #f7f8fc;
z-index: 9999999;
-webkit-transition: all 0.3s ease-in;
-o-transition: all 0.3s ease-in;
transition: all 0.3s ease-in;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
.load {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.loader {
display: block;
width: 120rpx;
height: 120rpx;
border-radius: 50%;
border: 8rpx solid transparent;
border-top-color: var(--primaryColor, #b3030e);
-webkit-animation: spin1 2s linear infinite;
animation: spin1 2s linear infinite;
}
.loader::before {
content: "";
position: absolute;
top: 8rpx;
left: 8rpx;
right: 8rpx;
bottom: 8rpx;
border-radius: 50%;
border: 8rpx solid transparent;
border-top-color: var(--primaryColor, #b3030e);
-webkit-animation: spin1 3s linear infinite;
animation: spin1 3s linear infinite;
}
.loader::after {
content: "";
position: absolute;
top: 24rpx;
left: 24rpx;
right: 24rpx;
bottom: 24rpx;
border-radius: 50%;
border: 8rpx solid transparent;
border-top-color: var(--primaryColor, #b3030e);
-webkit-animation: spin1 1.5s linear infinite;
animation: spin1 1.5s linear infinite;
}
@-webkit-keyframes spin1 {
0% {
-webkit-transform: rotate(0deg);
-ms-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
-ms-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes spin1 {
0% {
-webkit-transform: rotate(0deg);
-ms-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
-ms-transform: rotate(360deg);
transform: rotate(360deg);
}
}
}
</style>
1. 小程序讲解:
插件包:@/components/shop-decorater
插件的配置引入:类似 pages/index/config.js
【展示数据接口配置:decAxios,
页面操作方式:decEventHandler,
插件图片及在线图片管控:decImgDomain
样式的管控:@/components/shop-decorater/style/variable.less
2. 装修包可封成公用插件,插件遵循的修改规则如下:
少动插件包【@/components/shop-decorater】的逻辑代码
操作及交互方法多引入到配置文件中,
插件包的组件基本都是从 pc 端装修项目拷贝过来,逻辑及样式变动很小
@import "./variable.less";
@import "./common.less";
@import "../shopHead/index.less";
/** 组件样式引入 **/
@import "../shopFront/style/index.less";
@import "../shopSearch/style/index.less";
@import "../showLines/style/index.less";
@import "../shopNav/style/index.less";
@import "../goodList/style/index.less";
@import "../blockTitle/style/index.less";
@import "../descText/style/index.less";
@import "../richText/style/index.less";
@import "../imageLink/style/index.less";
@import "../voiceLink/style/index.less";
@import "../videoLink/style/index.less";
@import "../shopNotice/style/index.less";
@import "../shopTel/style/index.less";
@import "../imageBlock/style/index.less";
@import "../goodDiscount/style/index.less";
@import "../goodSpecial/style/index.less";
@import "../goodIntegral/index.less";
/* 商品列表中的商品名称默认为两行的设置 */
.dec-box-good {
.good-title.dec-truncate {
display: -webkit-box !important;
-webkit-line-clamp: 2;
white-space: inherit;
height: 50 * @rpx;
}
&.big .good-title {
height: auto;
}
&.small .good-title.dec-truncate {
height: 46 * @rpx;
}
}
// @import '../goodGroup/style/index.less';
// @import '../shopCoupon/style/index.less';
// @import '../shopGroup/style/index.less';
// @import '../toShopping/style/index.less';
// @import '../toBargain/style/index.less';
<template>
<view id="decoraterId" v-if="tabs && tabs.length > 0" :style="globalStyle">
<shopHead
v-if="header == 'in'"
:tab="shopBase"
:title="pageSet.pageName"
@inited="headInited"
@decEventHandler="headFn"
/>
<view v-for="(item, i) in tabs" :key="item.id" class="decorater-item">
<shopFront :tab="item" v-if="item.type === 'shopFront'" />
<shopSearch :tab="item" v-else-if="item.type === 'shopSearch'" />
<showBlank :tab="item" v-else-if="item.type === 'showBlank'" />
<showLines :tab="item" v-else-if="item.type === 'showLines'" />
<shopNav :tab="item" v-else-if="item.type === 'shopNav'" />
<goodList
ref="autoLoadRef"
:class="autoLoadAtBottom.ref == item.id ? 'autoLoadId' : 'noAuto'"
@inited="autoLoadInited"
:tab="item"
v-else-if="item.type === 'goodList'"
/>
<blockTitle :tab="item" v-else-if="item.type === 'blockTitle'" />
<descText :tab="item" v-else-if="item.type === 'descText'" />
<richText :tab="item" v-else-if="item.type === 'richText'" />
<imageLink :tab="item" v-else-if="item.type === 'imageLink'" />
<voiceLink :tab="item" v-else-if="item.type === 'voiceLink'" />
<videoLink :tab="item" v-else-if="item.type === 'videoLink'" />
<shopNotice :tab="item" v-else-if="item.type === 'shopNotice'" />
<shopTel :tab="item" v-else-if="item.type === 'shopTel'" />
<imageBlock :tab="item" v-else-if="item.type === 'imageBlock'" />
<goodDiscount :tab="item" v-else-if="item.type === 'goodDiscount'" />
<goodSpecial :tab="item" v-else-if="item.type === 'goodSpecial'" />
<goodFine :tab="item" v-else-if="item.type === 'goodFine'" />
<goodIntegral
ref="autoLoadRef"
:class="autoLoadAtBottom.ref == item.id ? 'autoLoadId' : 'noAuto'"
@inited="autoLoadInited"
:tab="item"
v-else-if="item.type === 'goodIntegral'"
/>
</view>
</view>
</template>
<script>
import shopHead from "./shopHead";
/** 店招 **/
import shopFront from "./shopFront";
/** 搜索框 **/
import shopSearch from "./shopSearch";
/** 空白 **/
import showBlank from "./showBlank";
/** 辅助线 **/
import showLines from "./showLines";
/** 导航栏 **/
import shopNav from "./shopNav";
/** 商品列表 **/
import goodList from "./goodList";
/** 标题 **/
import blockTitle from "./blockTitle";
/** 文本 **/
import descText from "./descText";
/** 富文本 **/
import richText from "./richText";
/** 广告 **/
import imageLink from "./imageLink";
/** 语音 **/
import voiceLink from "./voiceLink";
/** 视频 **/
import videoLink from "./videoLink";
/** 公告 **/
import shopNotice from "./shopNotice";
/** 客服电话 **/
import shopTel from "./shopTel";
/** 图块区 **/
import imageBlock from "./imageBlock";
/** 限时抢购 **/
import goodDiscount from "./goodDiscount";
/** 商品专区 **/
import goodSpecial from "./goodSpecial";
/** 优惠限购 **/
import goodFine from "./goodFine";
/** 积分商品 **/
import goodIntegral from "./goodIntegral";
export default {
name: "shop-decorater",
components: {
shopHead,
/** 装修组件start **/
shopFront,
shopSearch,
showBlank,
showLines,
shopNav,
goodList,
blockTitle,
descText,
richText,
imageLink,
voiceLink,
videoLink,
shopNotice,
shopTel,
imageBlock,
goodDiscount,
goodSpecial,
goodFine,
goodIntegral,
/** 装修组件end **/
},
inject: ["decAxios", "decImgDomain"],
props: {
header: {
type: String,
default: "in",
},
},
computed: {
globalStyle() {
if (this.header == "in") {
return this.getGlobalStyle();
} else {
return "";
}
},
},
data() {
return {
waiting: false,
tabs: [], // 左侧组件参数数组
paddingTop: 0,
autoLoadTop: 0,
autoLoadTopUpdate: 0,
autoLoadAtBottom: {},
componentMap: {},
pageSet: {
id: "0",
type: "pageSet",
name: "页面配置",
pageName: "首页", // 页面名称
pageDesc: "页面描述", // 页面描述
bgColor: "", // 页面背景色
},
shopBase: {
type: "shopBase",
mode: "", // 原生-高级custom
styleArg: "", //fix
fontColor: "black",
lIcon: "",
lIconImg: "",
lIconLink: {},
title: "",
search: false,
searchBg: "",
rIcon: false,
rIconFn: [],
rIconImg: "",
rIconCc: true,
rIconLink: {},
},
};
},
methods: {
initData(json) {
// 获取保存好的数据
let layout = [],
autoLoadAtBottom = {},
componentMap = {};
try {
const templateJson = JSON.parse(json); //JSON.parse(unescape(result.pageLayout));
let len = templateJson.length,
hasPageSet = false;
let pageSet, shopBase;
for (let i = len; i > 0; i--) {
const name = templateJson[i - 1].type;
if (name == "pageSet") {
hasPageSet = true;
pageSet = templateJson.splice(i - 1, 1);
} else if (name == "shopBase") {
shopBase = templateJson.splice(i - 1, 1);
}
}
layout = templateJson;
if (hasPageSet) {
this.pageSet = Object.assign({}, this.pageSet, pageSet[0]);
this.shopBase = Object.assign({}, this.shopBase, shopBase[0]);
} else {
this.pageSet = Object.assign({}, this.pageSet, shopBase[0]);
this.shopBase = this.shopBase;
}
//记录组件位置
const distance = this.header == "in" ? 1 : 0;
layout.forEach((item, i) => {
const name = item.type;
if (!componentMap[name]) componentMap[name] = [];
componentMap[name].push(i);
//判断最后组件是否是无限加载组件
if (layout.length == i + 1) {
if (["goodList", "goodIntegral"].includes(item.type)) {
if (item.arg.autoLoad == "Y") {
autoLoadAtBottom = {
name: item.type,
index: i - distance,
ref: item.id,
};
}
}
}
});
} catch (err) {
console.log("initData-err:", err);
}
console.log("initData-layout:", layout);
this.tabs = layout;
this.$emit("inited", {
count: layout.length,
pageName: this.pageSet.pageName,
navMode: this.shopBase.mode,
pageSet: this.pageSet,
shopBase: this.shopBase,
globalStyle: this.getGlobalStyle(),
autoLoadAtBottom,
});
this.componentMap = componentMap;
this.autoLoadAtBottom = autoLoadAtBottom;
},
getGlobalStyle() {
const arr = [
`background-color:${this.pageSet.bgColor};`,
`background-image: url('${this.pageSet.bgImg}')`,
`background-repeat:${this.pageSet.repeat ? "repeat" : "no-repeat"}`,
`background-size:${this.pageSet.repeat ? "" : "100% auto"}`,
];
return arr.join(";");
},
headInited(obj) {
this.paddingTop = (obj && obj.height) || 57;
},
autoLoadInited() {
//获取高度
const that = this;
const query = uni.createSelectorQuery().in(this);
query.select("#decoraterId").boundingClientRect();
query.select("#decoraterId .autoLoadId").boundingClientRect();
query.exec((res) => {
const totalH = res[0].height;
const loadH = res[1].height;
const autoLoadTop = totalH - loadH;
that.autoLoadTop = autoLoadTop;
that.autoLoadTopUpdate += 1;
});
},
pageScroll(top, fixTop) {
if (!this.waiting) {
this.waiting = true;
const i = this.autoLoadAtBottom.index || -1;
if (i > -1) {
const autoLoads = this.$refs.autoLoadRef;
const target = autoLoads[autoLoads.length - 1];
if (!target.setTabFixed) return;
if (this.autoLoadTopUpdate == 1 && this.autoLoadTop * 0.5 < top) {
this.autoLoadInited();
}
if (this.autoLoadTop < top) {
target.setTabFixed(true, fixTop || this.paddingTop); //设置tab固定
} else {
target.setTabFixed(false);
}
this.waiting = false;
}
}
},
pageShow() {
//现采用全局事件通信,此方法待用
console.log("$children-$children:", this.$children);
const findChild = (j) => {
const distance = this.header == "in" ? 1 : 0;
const i = j - distance;
let children = {};
// #ifdef H5
children = this.$children[0];
children = children[i];
// #endif
// #ifndef H5
children = this.$children[i];
// #endif
return children;
};
},
reachBottom() {
const i = this.autoLoadAtBottom.index || -1;
if (i > -1) {
console.log("autoLoad-reachBottom:", i);
const autoLoads = this.$refs.autoLoadRef;
const target = autoLoads[autoLoads.length - 1];
target.reachBottomFn && target.reachBottomFn();
}
},
headFn(params, link) {
this.decAxios.decEventHandler(params, link);
},
},
};
</script>
<template>
<view class="dec-blockTitle">
<text class="box" :class="arg.titleStyle">{{
arg.title || "右侧编辑『标题』"
}}</text>
<view class="more" v-if="arg.more === 'yes'" @tap="toNavLink(arg.linkArg)">
<text class="text">更多</text>
<view class="svg"></view>
</view>
</view>
</template>
<script>
// 设置标题
export default {
inject: ["decImgDomain", "decAxios"],
props: {
tab: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
arg: {},
};
},
created() {
this.arg = this.tab.arg;
},
methods: {
toNavLink(link) {
if (link && link.path) {
this.decAxios.decEventHandler(
{
moudle: "blockTitle",
type: "detail",
desc: "跳绑定的连接",
},
link,
null
);
}
},
},
};
</script>
.dec-blockTitle {
padding: @margin @space;
position: relative;
.box {
width: 100%;
display: block;
color: @color-head;
font-size: @font-big;
font-weight: bold;
text-align: left;
}
.center {
text-align: center;
}
.more {
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 48 * @rpx;
}
.text {
display: inline-block;
vertical-align: middle;
font-size: @font-base;
color: @color-text2;
}
.svg {
display: inline-block;
vertical-align: middle;
width: 12 * @rpx;
height: 12 * @rpx;
background-repeat: no-repeat;
background-position: center center;
background-size: 100% 100%;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAA4BJREFUaEPVms+LFEcUx7+ve9j/IAdP8aJXrzmGHHNPZkZU3Ox0V88kWXESJAQRRETE/MKVmXolIiEkhIQchEhccCEL2cQNWVAwEGEFFUUlSghZkSE786ShhGWxZrt7useevk71q89n+r3q7ldNSHEYY/YCeENEXheROaXU50QkKULkPpSSRux2u9s9z/sdwCsbzvkBQF0p9X/SOHmPSyzAzO8BmNsMQEQX1tbW6u12+2necEniJRbQWu8ioquOoBcrlUp9ZmbmvyST5jkmsUA8KTN/B+CtFwEQ0fz6+nq91Wr9kyfgVrFSCViJbwFUHYEXer1efXZ29u+tJs7r99QC8cRa62+IqO6AWLSFfT8vyGFxMgnYK/EVgD2OdFoioloQBHeLlsgsEIMZY74UkX0OyOXBYFBrNpu3ipQYScCm03ki2u+4Eiue59UajcZqURIjC9h0OgfgHQfkNQA1pdRfRUjkImAlzgJoOCD/tOl0PW+J3ASsBAMIHZA34sIOw9B1M8zklquArYkuEUUOmpsiUoui6I9MtC84KXcBeyXOAHjXAXk7LuwgCK7kIVGIgF1iT4vI+w7Ie7awfxlVojABm05fENEBB+RDW9g/jyJRqIBNp88AHHRAPraFfTmrROECVuITAB84IP+1hX0pi8RYBKzESQCHHJBPbDr9mFZibAJW4gSAjxyQPc/zqkEQXEgjMVYBK3EcwMcOyD4RVcMwjN+1Ex1jF7Cr0zEiOuwgvKOUejURPYCXImAljhLREQfo20qp75NIlFKAiN4Mw/Cn0gporYel0KpSakcS+HjM2K8AM09uETPz5C6jzDz0Rha3apRSF5OmzvNxY0khY8wpEfnQ9Shh1/75tPBjqQFjzKci0nY9zIlINYqihSzwhQtorYc+Ttt/Pm6EZT4KSyGt9Wkicr7Q+L5fbTQaS5nJ7YmFCDDz0FdKW7DLo8IXkkLM3AHQdMCV+6WemTUA5YAvd1vFGGNEJHDAl7uxxcyT21rUWjubuyKyUqlUytvcnej2OjM7NzhEZMn3/fJucDDz1wB2Owp2cWpqqjY9Pf0gj3V+qxipb2TMPHSTz7YMH201cV6/pxIYts0qIvODwaC826ydTuc13/d/c/xz5d/o7na7+z3PO79ZYGI+NWDmbQB+BbB9g8TkfOwRQxtjWvZTg539fv9sFEVxb+elfm7zDDUObUC4VvuTAAAAAElFTkSuQmCC");
}
}
<template>
<view class="dec-desc" :style="{ backgroundColor: arg.bgColor }">
<text
class="text"
v-for="(item, i) in desc"
:key="i + item"
:class="className"
:style="{ color: arg.color }"
>
{{ item }}
</text>
</view>
</template>
<script>
export default {
props: {
tab: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
arg: null,
className: "",
desc: [],
};
},
created() {
this.arg = this.tab.arg;
this.initData();
},
methods: {
initData() {
if (!!this.arg.title) {
const title = this.arg.title.replace(/\n\r?/g, "<br>");
this.desc = title.split("<br>");
} else {
this.desc = ["左侧编辑『文本内容』"];
}
this.className = (function (that) {
let str = "";
if (!!that.arg.size) {
str = that.arg.size;
}
if (!!that.arg.position) {
str = str + (str ? " " : "") + that.arg.position;
}
return str;
})(this);
},
},
};
</script>
.dec-desc {
padding: @margin @space;
.text {
text-align: left;
color: @color-text;
font-size: @font-base;
margin: 0;
display: block;
}
.big {
font-size: @font-big;
}
.small {
font-size: @font-small;
}
.right {
text-align: right;
}
.center {
text-align: center;
}
}
<template>
<view class="dec-discount-s-good" :class="className" @tap="go">
<view class="image" :style="{ height: imgH }">
<image
class="img"
mode="aspectFill"
:src="decImgDomain(good.productImg || '')"
alt=""
/>
</view>
<view class="flex time" v-if="imgArg != 'small' && show.time">
<text class="start">{{ inLine }}</text>
<view class="limit">
<template v-if="inLine2">
<text>{{ inLine2 }}</text
><br />
</template>
<text>{{ endTime }}</text>
</view>
</view>
<view class="info">
<view class="title dec-truncate2" v-if="show.title">
{{ good.productName }}
</view>
<view class="desc dec-truncate" v-if="show.desc">{{
good.introduction || good.productName
}}</view>
<!-- 价格 购买 -->
<view
class="price-wrap dec-row-flex a-bottom"
v-if="show.price || show.origin"
>
<text class="dot" v-if="show.price">¥</text>
<text class="sale" v-if="show.price">
{{ good.activityPrice || 0 }}</text
>
<text class="origin" v-if="opriceShow">¥{{ good.smarketPrice }}</text>
</view>
</view>
</view>
</template>
<script>
export default {
inject: ["decImgDomain", "decAxios"],
props: {
good: {
type: Object,
default: () => {
return {};
},
},
show: {
type: Object,
default: () => {
return {};
},
},
imgArg: {
type: String,
default: "",
},
imgH: {
type: String,
default: "auto",
},
time: {
type: Object,
default: () => {
return {};
},
},
state: {
type: String,
default: "",
},
},
computed: {
endTime() {
if (!this.time.hour) {
return "活动" + (this.state || "未开始");
}
if (this.imgArg == "big") {
if (this.time.day) {
return `${this.time.day}${this.time.hour}${this.time.minutes}${this.time.seconds}`;
}
return `${this.time.hour}${this.time.minutes}${this.time.seconds}`;
} else {
const arr = (this.good.limit || "--").split("-");
if (this.time.day) {
return `${this.time.day}天:${this.time.hour}:${this.time.minutes}:${this.time.seconds}`;
}
return `${this.time.hour}:${this.time.minutes}:${this.time.seconds}`;
}
},
inLine() {
let name = "";
if (this.imgArg == "big") {
name = ["已结束", "未开始"].includes(this.state) ? "" : "限时抢购";
} else {
name = ["已结束", "未开始"].includes(this.state) ? "" : "距结束";
}
return name;
},
inLine2() {
let name = "";
if (this.imgArg == "big") {
name = ["已结束", "未开始"].includes(this.state)
? "活动状态"
: "距结束仅剩";
}
return name;
},
remain() {
return parseInt(this.good.activityStock - this.good.saleCount);
},
className() {
let str = [];
if (this.imgArg) str.push(this.imgArg);
if (this.show.border) str.push(this.show.border);
if (this.show.radius) str.push("radius");
return str;
},
opriceShow() {
if (this.show.origin && this.good.smarketPrice) {
return this.good.smarketPrice > this.good.activityPrice;
}
return false;
},
},
methods: {
go() {
this.decAxios.decEventHandler(
{
moudle: "goodDiscount",
type: "detail",
desc: "跳折扣商品详情页",
},
this.good,
null
);
},
buy() {
this.decAxios.decEventHandler(
{
moudle: "goodDiscount",
type: "buy",
desc: "购买折扣商品",
},
this.good,
null
);
},
},
};
</script>
<template>
<view class="dec-discount-l-good" :class="className" @tap="go">
<!-- 图片 角标 -->
<view class="good-image" :style="{ width: imgW, height: imgW }">
<image
class="img"
mode="widthFix"
:src="decImgDomain(good.productImg || '')"
/>
<view class="time flex" v-if="show.time">
<text class="start">{{ inLine }}</text>
<text>{{ endTime }}</text>
</view>
</view>
<view class="info">
<view class="intro">
<view class="title dec-truncate2 mb" v-if="show.title">
{{ good.productName }}
</view>
<view class="desc dec-truncate mb" v-if="show.desc">{{
good.introduction || good.productName
}}</view>
</view>
<!-- 价格 购买 -->
<view
class="price-wrap dec-row-flex a-bottom"
v-if="show.price || show.origin"
>
<text class="dot" v-if="show.price">¥</text>
<text class="sale" v-if="show.price">
{{ good.activityPrice || 0 }}</text
>
<text class="origin" v-if="opriceShow">{{ good.smarketPrice }}</text>
</view>
</view>
</view>
</template>
<script>
export default {
inject: ["decImgDomain", "decAxios"],
props: {
show: {
type: Object,
default: () => {
return {};
},
},
good: {
type: Object,
default: () => {
return {};
},
},
imgArg: {
type: String,
default: "",
},
imgW: {
type: String,
default: "36%",
},
time: {
type: Object,
default: () => {
return {};
},
},
state: {
type: String,
default: "",
},
},
computed: {
endTime() {
if (!this.time.hour) {
return "活动" + this.state;
}
if (this.time.day) {
return `${this.time.day}天:${this.time.hour}:${this.time.minutes}:${this.time.seconds}`;
}
return `${this.time.hour}:${this.time.minutes}:${this.time.seconds}`;
},
inLine() {
return ["已结束", "未开始"].includes(this.state) ? "" : "距结束";
},
remain() {
return parseInt(this.good.activityStock - this.good.saleCount);
},
className() {
let str = [];
if (this.imgArg) str.push(this.imgArg);
if (this.show.border) str.push(this.show.border);
if (this.show.radius) str.push("radius");
return str;
},
opriceShow() {
if (this.show.origin && this.good.smarketPrice) {
return this.good.smarketPrice > this.good.activityPrice;
}
return false;
},
},
methods: {
go() {
this.decAxios.decEventHandler(
{
moudle: "goodDiscount",
type: "detail",
desc: "跳折扣商品详情页",
},
this.good,
null
);
},
buy() {
this.decAxios.decEventHandler(
{
moudle: "goodDiscount",
type: "buy",
desc: "购买折扣商品",
},
this.good,
null
);
},
},
};
</script>
// 中:13px 12px 16px[6]
// 大:16px 12px 20px[10]
.dec-discount-s-good {
background: #ffffff;
overflow: hidden;
&.shadow {
box-shadow: @shadow-good;
}
&.border {
border: 1px solid #e5e5e5;
}
&.none {
background: transparent;
}
&.radius {
border-radius: 12 * @rpx;
}
.flex {
display: flex;
align-items: center;
justify-content: space-between;
}
.em {
color: @color-tip;
}
.mb {
margin-bottom: 6 * @rpx;
}
&.big .mb {
margin-bottom: 10 * @rpx;
}
.image {
font-size: 0;
overflow: hidden;
.img {
width: 100%;
height: 100%;
}
}
.time {
padding: 5 * @rpx 10 * @rpx;
background: linear-gradient(to right, #f86f30, #e91717);
}
.start {
font-size: @font-sub;
color: #ffffff;
}
&.big .start {
font-size: @font-super;
}
.limit {
font-size: @font-sub;
color: #ffffff;
}
.info {
padding: 6 * @rpx 10 * @rpx;
}
&.big .info {
padding: 10 * @rpx;
}
.title {
color: @color-text;
font-size: @font-base;
height: 38 * @rpx;
white-space: initial;
}
&.big .title {
font-size: @font-middle;
height: auto;
}
&.small .title {
line-height: 1.4;
}
.mark {
display: inline-block;
height: 16 * @rpx;
line-height: 16 * @rpx;
font-size: @font-small;
border-radius: 8 * @rpx;
color: @color-tip;
background-color: #f1c4c4;
padding: 0 6 * @rpx;
margin-right: 5 * @rpx;
max-width: 100 * @rpx;
overflow: hidden;
vertical-align: middle;
}
.desc {
color: @color-text3;
font-size: @font-sub;
&.dec-truncate {
display: block;
}
}
.progress {
background: #dcdee0;
height: 6 * @rpx;
border-radius: 3 * @rpx;
.dot {
background: @color-tip;
width: 50%;
height: 6 * @rpx;
border-radius: 3 * @rpx;
}
}
.remain {
font-size: @font-sub;
color: @color-text3;
}
.price-wrap {
.dot {
font-size: @font-base;
padding: 10 * @rpx 0;
padding-left: 0; //10 * @rpx;
padding-right: 2 * @rpx;
color: @color-theme;
line-height: 1;
}
.sale {
display: inline-block;
color: @color-theme;
font-size: @font-middle;
padding: 10 * @rpx 0;
padding-right: 6 * @rpx;
line-height: 1;
}
.origin {
color: @color-text2;
font-size: @font-sub;
text-decoration: line-through;
padding: 10 * @rpx 0;
padding-right: 4 * @rpx;
line-height: 1;
}
}
//特殊样式处理
&.big .price-wrap {
.sale {
font-size: 22 * @rpx;
}
}
&.small .price-wrap {
.sale {
font-size: @font-base;
}
}
}
// 大:14px 12px 18px[10]
.dec-discount-l-good {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
background-color: #ffffff;
overflow: hidden;
&.shadow {
box-shadow: @shadow-good;
}
&.border {
border: 1px solid #e5e5e5;
}
&.none {
background: transparent;
}
&.radius {
border-radius: 12 * @rpx;
}
.flex {
display: flex;
align-items: center;
justify-content: space-between;
}
.em {
color: @color-tip;
}
.mb {
margin-bottom: 6 * @rpx;
}
.good-image {
margin: 0;
position: relative;
width: 36%;
font-size: 0;
min-height: 118px;
.img {
width: 100%;
}
}
.time {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
background: linear-gradient(to right, #f86f30, #e91717);
font-size: @font-small;
padding: 4 * @rpx;
color: #ffffff;
}
.start {
font-size: @font-small;
color: #ffffff;
}
.info {
width: 64%;
flex-shrink: 2;
position: relative;
background: #ffffff;
}
.intro {
padding: 12 * @rpx 10 * @rpx;
}
.title {
color: @color-text;
font-size: @font-middle;
}
.mark {
display: inline-block;
height: 16 * @rpx;
line-height: 16 * @rpx;
font-size: @font-small;
border-radius: 8 * @rpx;
color: @color-tip;
background-color: #f1c4c4;
padding: 0 6 * @rpx;
margin-right: 5 * @rpx;
max-width: 100 * @rpx;
overflow: hidden;
vertical-align: middle;
}
.desc {
color: @color-text3;
font-size: @font-small;
display: block;
}
.progress {
background: #dcdee0;
height: 6 * @rpx;
border-radius: 3 * @rpx;
.dot {
background: @color-tip;
width: 50%;
height: 6 * @rpx;
border-radius: 3 * @rpx;
}
}
.remain {
font-size: @font-small;
color: @color-text3;
}
.price-wrap {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: 6 * @rpx 0;
box-sizing: border-box;
.dot {
font-size: @font-base;
padding: 10 * @rpx 0;
padding-left: 10 * @rpx;
padding-right: 2 * @rpx;
color: @color-theme;
line-height: 1;
}
.sale {
display: inline-block;
color: @color-theme;
font-size: 22 * @rpx;
padding: 10 * @rpx 0;
padding-right: 6 * @rpx;
line-height: 1;
}
.origin {
color: @color-text2;
font-size: @font-sub;
text-decoration: line-through;
padding: 10 * @rpx 0;
padding-right: 4 * @rpx;
line-height: 1;
}
}
}
@import "./goodBox.less";
@import "./goodLong.less";
.dec-discount {
.ts-wrap {
position: relative;
}
.ts-title {
display: flex;
flex-direction: row;
align-items: center;
flex-wrap: nowrap;
justify-content: center;
background-color: @color-bg;
padding: 10 * @rpx 0;
margin-bottom: 5 * @rpx;
}
.ts-text {
color: @color-head;
padding: 0 16 * @rpx;
font-size: @font-middle;
}
.ts-line {
height: 2 * @rpx;
width: 30 * @rpx;
background-color: @color-border;
}
.ts-more {
position: absolute;
top: 12 * @rpx;
right: 10 * @rpx;
color: @color-text2;
}
.list-wrap {
padding: @lacuna2 @space;
}
.big-wrap {
.item {
padding: 0 @space @lacuna;
}
}
.two-wrap {
display: flex;
flex-wrap: wrap;
flex-direction: row;
padding: 0 @space2;
.item {
box-sizing: border-box;
width: 50%;
padding: @lacuna2;
}
}
.limit-time {
display: flex;
font-size: @font-middle;
color: @color-tip;
align-items: center;
padding: @space @space 0;
border-radius: 4 * @rpx;
.box {
display: inline-block;
font-size: @font-small;
background: @color-tip;
padding: 4 * @rpx;
line-height: 1;
color: #ffffff;
margin-left: 2 * @rpx;
border-radius: 10rpx;
}
.box2 {
color: @color-tip;
}
.box3 {
padding: 0 8 * @rpx;
font-size: @font-small;
color: #ffffff;
background: #999;
}
}
.three-wrap {
display: flex;
flex-wrap: wrap;
flex-direction: row;
padding: 0 @space2;
.item {
box-sizing: border-box;
width: 33.33%;
padding: @lacuna2;
}
}
.scroll-X {
white-space: nowrap;
width: 100%;
margin-bottom: @space;
.item {
display: inline-block;
box-sizing: border-box;
width: 30%;
}
}
}
<template>
<view class="dec-goodSpecial" :style="className" v-if="bgImg" @tap="go">
<image class="img" mode="widthFix" :src="bgImg" />
</view>
</template>
<script>
// 设置分组
export default {
inject: ["decAxios", "decImgDomain"],
props: {
tab: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
bgImg: "",
};
},
computed: {
className() {
const arg = this.tab.arg;
let arr = [];
if (arg.space) arr.push(`margin: 0 ${arg.space}px`);
if (arg.radius) arr.push(`borderRadius: ${arg.radius}px`);
if (arg.bgColor && arg.bgColor != "transparent")
arr.push(`background-color: ${arg.bgColor}`);
if (arg.bgSize) arr.push(`padding: 0 ${50 - arg.bgSize * 0.5}%`);
return arr.join(";");
},
},
created() {
const arg = this.tab.arg;
const api = this.decAxios.getGoodFineData;
const select = arg.id,
that = this;
if (select.id) {
api({ id: select.id }).then(({ code, result }) => {
that.bgImg = "";
if (code == 200) {
result = result || {};
const endTime = (result.endTime || "2022-5-20").replace(/-/g, "/");
const startTime = (result.startTime || "2022-5-20").replace(
/-/g,
"/"
);
if (that.initTime(endTime, startTime) != "end") {
that.bgImg = that.decImgDomain(result.picture);
}
}
});
} else {
this.bgImg = "";
}
},
methods: {
initTime(endTime, startTime) {
const end = new Date(endTime),
start = new Date(startTime),
current = new Date();
let state = "";
if (current - start > 0) {
if (end - current > 0) {
state = "ing";
} else {
state = "end";
}
} else {
state = "start";
}
return state;
},
go() {
this.decAxios.decEventHandler(
{
moudle: "goodFine",
type: "detail",
desc: "跳优惠限购活动页",
},
this.tab.arg.id,
null
);
},
},
};
</script>
<template>
<!-- 区分是否是固定高度的还是非固定高度-默认传了图片高度就是要统一高度 -->
<view class="dec-box-good" :class="className" @tap.stop="go">
<!-- 图片 角标 dec-row-flex -->
<view class="good-img" :style="{ height: imgH }">
<image
v-if="imgH"
class="imgH"
:src="decImgDomain(good.targetImg)"
mode="aspectFill"
/>
<image
v-else
class="imgW"
:src="decImgDomain(good.targetImg)"
mode="widthFix"
/>
</view>
<!-- 名称 -->
<view class="good-info dec-row-flex">
<view class="good-title" :class="titleClass">{{ good.targetName }}</view>
</view>
<!-- 价格 购买 -->
<view class="price-sale">
{{ salePrice }}
</view>
<!-- 剩余多少件 -->
<view class="good-stock" v-if="show.stock">
<text class="text dec-truncate">剩余{{ good.stock || 0 }}</text>
</view>
<!-- 到期时间 -->
<!-- <view class="good-valid" v-if="show.stop">
<text class="text dec-truncate">{{good.endTime}}到期</text>
</view> -->
</view>
</template>
<script>
export default {
inject: ["decImgDomain", "decAxios"],
props: {
moudle: {
type: String,
default: "goodList",
},
good: {
type: Object,
default: () => {
return {};
},
},
show: {
type: Object,
default: () => {
return {};
},
},
imgArg: {
type: String,
default: "", // big middle small
},
imgH: {
type: String,
default: "",
},
},
computed: {
className() {
let str = [];
if (this.imgArg) str.push(this.imgArg);
if (this.show.radius) str.push("radius");
return str;
},
titleClass() {
if (!this.imgH) {
return "dec-truncate2";
} else {
return "dec-truncate";
}
},
hasShop() {
const hasShop = this.show.price || this.show.origin;
const hasShop2 = this.show.bug && this.imgArg != "small";
return hasShop || hasShop2;
},
salePrice() {
let arr = [];
if (this.good.integral && this.good.integral > 0)
arr.push(this.good.integral + "积分");
if (this.good.paymentAmount && this.good.paymentAmount > 0)
arr.push(this.good.paymentAmount + "元");
return arr.length > 0 ? arr.join("+") : 0;
},
},
methods: {
go() {
this.decAxios.decEventHandler(
{
moudle: this.moudle,
type: "detail",
desc: "跳商品详情页",
},
this.good,
null
);
},
buy() {
this.decAxios.decEventHandler(
{
moudle: this.moudle,
type: "buy",
desc: "购买商品",
},
this.good,
null
);
},
},
};
</script>
<template>
<view class="item-wrap" v-if="goods && goods.length > 0">
<view v-for="(product, p) in goods" :key="p" class="item">
<good-short
:moudle="moudle"
:good="product"
:show="show"
:imgH="img.h2"
/>
</view>
</view>
</template>
<script>
// 设置列表
import goodShort from "./goodShort.vue";
export default {
components: {
goodShort,
},
props: {
moudle: {
type: String,
default: "goodIntegral",
},
arg: {
type: String,
default: "",
},
groupKey: {
type: String,
default: "left",
},
goodKey: {
type: String,
default: "",
},
},
data() {
return {
goods: [],
show: {},
img: {},
};
},
created() {
const dataKey = `${this.groupKey}-${this.goodKey}`;
let parent = {};
// #ifdef H5
parent = this.$parent.$parent.$parent;
if (!parent.allGoods) parent = parent.$parent;
if (!parent.allGoods) parent = parent.$parent;
if (!parent.allGoods) parent = parent.$parent;
// #endif
// #ifndef H5
parent = this.$parent;
// #endif
if (parent.allGoods) {
this.goods = parent.allGoods[dataKey];
this.img = parent.img;
this.show = parent.show;
}
},
computed: {
scrollH() {
if (this.arg == "scroll-two") {
const h = parseInt((this.img.h2 || "").replace("px", "")) + 14;
return h + "px";
} else if (this.arg == "scroll-three") {
const h = parseInt((this.img.h3 || "").replace("px", "")) + 14;
return h + "px";
}
return "";
},
},
watch: {
goodKey(val) {
if (val) {
const dataKey = `${this.groupKey}-${this.goodKey}`;
this.goods = this.$parent.allGoods[dataKey];
}
},
},
};
</script>
.dec-goodList {
.group-tab {
height: 40 * @rpx;
background: #ffffff;
margin-bottom: 10 * @rpx;
}
.tab-wrap {
width: 100%;
display: flex;
justify-content: space-evenly;
align-items: center;
height: 40 * @rpx;
z-index: 2;
box-shadow: @shadow-good;
background: #ffffff;
}
.tab-item {
display: flex;
align-items: center;
justify-content: center;
position: relative;
font-size: @font-base;
font-weight: 400;
color: @color-head;
text-align: left;
flex-wrap: nowrap;
flex-shrink: 2;
padding: 0;
position: relative;
&::after {
content: "";
position: absolute;
bottom: 0;
width: 20 * @rpx;
height: 2 * @rpx;
background: transparent;
}
.text {
display: inline-block;
padding: 8 * @rpx 0;
}
&.active {
color: @color-theme;
font-weight: bold;
&::after {
background: @color-theme;
}
}
}
.dec-box-good {
.price-sale {
font-size: @font-base;
font-weight: 600;
margin: 4 * @rpx 10 * @rpx;
color: #ec6560;
}
.good-stock {
margin: 4 * @rpx 10 * @rpx;
.text {
color: @color-text3;
font-size: @font-base;
}
}
.good-valid {
margin: 4 * @rpx 10 * @rpx;
.text {
color: @color-text3;
font-size: @font-base;
}
}
}
}
<template>
<view class="dec-goodList" v-if="showGoods.length > 0">
<view class="group-tab">
<view class="tab-wrap" :style="fixedStyle">
<view
v-for="(item, i) in tabs"
:key="item"
class="tab-item"
:class="{ active: activeTab == i }"
@tap="tabClick(i)"
>
<text class="text">{{ item }}</text>
</view>
</view>
</view>
<view class="group-wrap">
<view
v-for="key in groups"
:key="key"
class="group two-group"
style="width: 50%"
>
<goodWrap
moudle="goodIntegral"
v-for="code in showGoods"
:key="code"
arg="two"
:groupKey="key"
:goodKey="code"
/>
</view>
</view>
<li-load-more v-if="arg.autoLoad == 'Y'" :status="loadMore" />
</view>
</template>
<script>
// 设置列表
import variable from "../style/variable.js";
import goodWrap from "./goodWrap";
export default {
inject: ["decAxios", "decImgDomain"],
components: { goodWrap },
props: {
tab: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
loading: false,
loadMore: "",
arg: {},
show: null,
isStatic: false,
activeTab: 0,
fixedStyle: "",
tabs: ["全部", "1-1000", "1001-5000", "5001-10000", "10000以上"],
groups: ["left", "right"], //数据组
allGoods: {}, //所有数据集合
showGoods: [], //显示的商品数据
pager: {
tab: 0,
pages: 0,
pageNo: 0, //页面页码
pageSize: 30,
},
img: {
h2: "",
},
};
},
onUnload() {
this.loadMore = "";
},
created() {
this.arg = this.tab.arg;
this.show = this.arg.show;
//图片直接默认是正方形图片
const w2 = variable["@phoneWidth"] - variable["@space"] * 3;
const h2 = parseInt(w2 * 50);
this.img.h2 = uni.upx2px(h2) / 100 + "px";
this.pager.pageNo = 0;
this.initApiData(true);
},
methods: {
tabClick(index) {
if (this.activeTab != index) {
(this.pager = {
tab: index,
pages: 0,
pageNo: 0,
pageSize: 30,
}),
this.initApiData(true);
}
},
initApiData(isInit) {
if (!this.loading) {
this.loading = true;
const api = this.decAxios.getGoodIntegralData;
const { tab, pages, pageSize } = this.pager;
let pageNo = this.pager.pageNo;
pageNo = pageNo + 1;
//处理参数
let params = { range: this.tabs[tab] };
if (this.arg.autoLoad == "Y") {
params = Object.assign({}, params, { pageNo, pageSize });
} else {
const pageSize2 = this.arg.dataNum || pageSize;
params = Object.assign({}, params, { pageNo, pageSize: pageSize2 });
}
//获取数据
api(params).then((res) => {
this.loading = false;
const result = res.result || {};
const records =
res.code == "200" ? result.records || result || [] : [];
const goodList = this.listStyleChange(records) || { left: [] };
const pageKey = `${tab}-${pageNo}-${pageSize}`;
//加入到数据源中
if (pageNo == 1) {
this.allGoods = {};
this.showGoods = [];
}
this.groups.forEach((val) => {
const key = `${val}-${pageKey}`;
this.allGoods[key] = goodList[val];
});
//页码更新
this.activeTab = tab;
this.pager.pages = result.pages || 1;
this.pager.pageNo = params.pageNo || 1;
//初次加载需要进行额外请求一次
if (isInit) {
this.reachBottomFn();
if (this.arg.autoLoad == "Y") this.$emit("inited");
} else {
this.loadMore = "";
}
});
}
},
reachBottomFn() {
const { tab, pageNo, pageSize, pages } = this.pager;
const showKey = `${tab}-${pageNo}-${pageSize}`;
this.loadMore = "";
if (this.arg.autoLoad != "Y" || this.loading) {
if (!this.showGoods.includes(showKey)) this.showGoods.push(showKey);
} else if (pageNo > 0 && pageNo == pages) {
if (!this.showGoods.includes(showKey)) this.showGoods.push(showKey);
this.loadMore = "noMore";
} else {
this.loadMore = "loading";
if (!this.showGoods.includes(showKey)) this.showGoods.push(showKey);
this.initApiData();
}
},
setTabFixed(val, fixTop) {
const fixedStyle = val ? `position:fixed;top:${fixTop}px;left:0;` : "";
this.fixedStyle = fixedStyle;
},
listStyleChange(res) {
let newRes = { right: [], left: [] };
res.forEach((item, i) => {
if ((i + 1) % 2 == 1) {
newRes.left.push(item);
} else {
newRes.right.push(item);
}
});
return newRes;
},
},
};
</script>
<template>
<view class="dec-img-good" :class="className" @tap.stop="go">
<image
class="good-img"
v-if="imgH"
:style="{ height: imgH }"
:src="decImgDomain(good.productImg)"
mode="aspectFill"
/>
<image
class="good-img"
v-else
:src="decImgDomain(good.productImg)"
:mode="imgArg == 'big' ? 'widthFix' : 'aspectFill'"
/>
<view class="good-info" :class="show.nameStyle">
<view class="good-title dec-truncate2" :class="show.nameStyle">{{
good.productName
}}</view>
<view class="price-wrap dec-row-flex j-between" v-if="!simple">
<view class="dec-row-flex a-bottom" v-if="show.price">
<view class="dot"></view>
<view class="sale">{{ good.salePrice || 0 }}</view>
<view class="origin" :class="show.nameStyle" v-if="opriceShow"
>{{ good.smarketPrice }}</view
>
</view>
<view class="good-reward" v-if="show.reward && predictReward"
>预计返{{ predictReward }}</view
>
</view>
</view>
</view>
</template>
<script>
export default {
inject: ["decImgDomain", "decAxios"],
props: {
moudle: {
type: String,
default: "goodList",
},
simple: {
type: Boolean,
default: true,
},
show: {
type: Object,
default: () => {
return {};
},
},
good: {
type: Object,
default: () => {
return {};
},
},
imgArg: {
type: String,
default: "",
},
imgH: {
type: String,
default: "",
},
},
computed: {
className() {
let str = [];
if (this.imgArg) str.push(this.imgArg);
if (this.show.radius) str.push("radius");
return str;
},
predictReward() {
let val = this.good.predictReward || 0;
val = parseInt(val * 100);
if (val > 0) {
val = `${val / 100}`;
const arr = val.split(".");
if (arr[1]) {
val = arr[1].length == 1 ? `${arr[0]}.${arr[1]}0` : val;
} else {
val = `${val}.00`;
}
} else {
val = "";
}
return val;
},
opriceShow() {
if (this.show.origin && this.good.smarketPrice) {
return this.good.smarketPrice > this.good.salePrice;
}
return false;
},
},
methods: {
go() {
this.decAxios.decEventHandler(
{
moudle: this.moudle,
type: "buy",
desc: "跳商品详情页",
},
this.good,
null
);
},
},
};
</script>
<template>
<view class="dec-long-good" :class="className" @tap.stop="go">
<!-- 图片 角标 -->
<view class="good-img" :style="{ width: imgW, height: imgW }">
<image
mode="widthFix"
class="img"
:src="decImgDomain(good.productImg || '')"
/>
<view class="mark" :class="show.markStyle" v-if="show.mark"></view>
</view>
<view class="good-info">
<view class="good-intro">
<view class="good-title dec-truncate2 mb" v-if="show.name">
{{ good.productName }}
</view>
<view class="good-desc dec-truncate" v-if="show.desc">
{{ good.productDesc || good.productName }}
</view>
</view>
<!-- 店铺名称|@tap.stop="goShop" -->
<view
v-if="show.shopName && good.shopName"
class="shop-name dec-truncate"
>{{ good.shopName || "所属店铺" }}</view
>
<!-- 商品佣金 -->
<view v-if="show.reward && predictReward" class="good-reward"
>预计返{{ predictReward }}</view
>
<!-- 价格 购买 -->
<view class="price-wrap dec-row-flex j-between" v-if="hasShop">
<view
class="dec-row-flex a-bottom shrink1"
v-if="show.price || show.origin || show.bug"
>
<text class="dot" v-if="show.price">¥</text>
<text class="sale" v-if="show.price"> {{ good.salePrice || 0 }}</text>
<text class="origin" v-if="opriceShow"
>{{ good.smarketPrice }}</text
>
</view>
<template v-if="show.bug">
<view
class="shrink0 b-buy"
v-if="show.bugStyle == 'custom'"
@tap.stop="buy"
>
<text>{{ show.bugTxt }}</text>
</view>
<view
class="shrink0 c-buy"
v-else-if="show.bugStyle == 'custom2'"
@tap.stop="buy"
>
<text>{{ show.bugTxt }}</text>
</view>
<view
class="shrink0 d-buy"
v-else-if="show.bugStyle == 'shop3'"
@tap.stop="buy"
>
<view class="cart-circle">
<uni-icons type="cart" :size="18" color="#ffffff" />
<text v-if="cartNum > 0" class="count">{{ cartNum }}</text>
</view>
</view>
<view class="shrink0 a-buy" v-else @tap.stop="buy">
<view class="text" v-if="show.bugStyle == 'shop'" @tap.stop="buy">
<uni-icons
type="cart-filled"
:size="imgArg == 'big' ? 40 : 34"
color="#ff4444"
/>
<text v-if="cartNum > 0" class="count">{{ cartNum }}</text>
</view>
<view
class="text"
v-else-if="show.bugStyle == 'shop2'"
@tap.stop="buy"
>
<uni-icons
type="cart"
:size="imgArg == 'big' ? 40 : 34"
color="#ff4444"
/>
<text v-if="cartNum > 0" class="count">{{ cartNum }}</text>
</view>
<view
class="text"
v-else-if="show.bugStyle == 'plus'"
@tap.stop="buy"
>
<uni-icons
type="plus-filled"
:size="imgArg == 'big' ? 40 : 34"
color="#ff4444"
/>
<text v-if="cartNum > 0" class="count">{{ cartNum }}</text>
</view>
<view
class="text"
v-else-if="show.bugStyle == 'plus2'"
@tap.stop="buy"
>
<uni-icons
type="plus"
:size="imgArg == 'big' ? 40 : 34"
color="#ff4444"
/>
<text v-if="cartNum > 0" class="count">{{ cartNum }}</text>
</view>
</view>
</template>
</view>
</view>
</view>
</template>
<script>
export default {
inject: ["decImgDomain", "decAxios"],
props: {
moudle: {
type: String,
default: "goodList",
},
show: {
type: Object,
default: () => {
return {};
},
},
good: {
type: Object,
default: () => {
return {};
},
},
count: {
type: Number,
default: 0,
},
imgArg: {
type: String,
default: "",
},
imgW: {
type: String,
default: "40%",
},
},
data() {
return {
cartNum: 0,
};
},
watch: {
count(val, val2) {
if (val != val2) this.cartNum = val || 0;
},
},
computed: {
className() {
let str = [];
if (this.imgArg) str.push(this.imgArg);
if (this.show.radius) str.push("radius");
return str;
},
hasShop() {
const hasShop = this.show.price || this.show.origin || this.show.bug;
return hasShop;
},
predictReward() {
let val = this.good.predictReward || 0;
val = parseInt(val * 100);
if (val > 0) {
val = `${val / 100}`;
const arr = val.split(".");
if (arr[1]) {
val = arr[1].length == 1 ? `${arr[0]}.${arr[1]}0` : val;
} else {
val = `${val}.00`;
}
} else {
val = "";
}
return val;
},
opriceShow() {
if (this.show.origin && this.good.smarketPrice) {
return this.good.smarketPrice > this.good.salePrice;
}
return false;
},
},
created() {
this.cartNum = this.count || 0;
},
methods: {
go() {
this.decAxios.decEventHandler(
{
moudle: this.moudle,
type: "detail",
desc: "跳商品详情页",
},
this.good,
null
);
},
buy() {
const that = this;
this.decAxios.decEventHandler(
{
moudle: this.moudle,
type: "buy",
desc: "购买商品",
},
this.good,
(obj) => {
that.cartNum = obj[that.good.id] || 0;
that.$emit("refreshBuyNum", obj);
}
);
},
goShop() {
this.decAxios.decEventHandler(
{
moudle: this.moudle,
type: "shop",
desc: "跳所属店铺",
},
this.good,
null
);
},
},
};
</script>
<template>
<!-- 区分是否是固定高度的还是非固定高度-默认传了图片高度就是要统一高度 -->
<view class="dec-box-good" :class="className" @tap.stop="go">
<!-- 图片 角标 dec-row-flex -->
<view class="good-img" :style="{ height: imgH }">
<image
v-if="imgH"
class="imgH"
:src="decImgDomain(good.productImg)"
mode="aspectFit"
/>
<image
v-else
class="imgW"
:src="decImgDomain(good.productImg)"
mode="widthFix"
/>
<view class="mark" :class="show.markStyle" v-if="show.mark"></view>
</view>
<!-- 名称 -->
<view class="good-info" v-if="show.name || show.desc">
<view class="good-title" :class="titleClass" v-if="show.name">{{
good.productName
}}</view>
<view class="good-desc dec-truncate" v-if="show.desc">
{{ good.productDesc || good.productName }}
</view>
</view>
<view class="tag-wrap" v-if="show.postType || show.reward">
<!-- 发货模式tag -->
<template v-if="postTypeShow">
<view
class="post-type dec-truncate"
:class="{ 'no-text': !good.postType }"
>
<template v-if="good.postType">
{{ postName[good.postType] || "未知" }}
</template>
</view>
</template>
<!-- tag形式的返佣 -->
<template v-if="tagRewardShow">
<view
class="discount-name dec-truncate"
:class="{ 'no-text': !predictReward }"
>
<template v-if="predictReward">
<text class="flag"></text>{{ predictReward }}
</template>
</view>
</template>
</view>
<!-- 价格 购买|兼容点击宽高问题 -->
<view class="price-wrap dec-row-flex j-between" v-if="hasShop">
<view
class="dec-row-flex a-bottom shrink1"
v-if="show.price || show.origin || show.bug"
>
<text class="dot" v-if="show.price">¥</text>
<text class="sale" v-if="show.price"> {{ good.salePrice || 0 }}</text>
<text class="origin" v-if="opriceShow">¥{{ good.smarketPrice }}</text>
</view>
<template v-if="show.bug && imgArg != 'small'">
<view
class="shrink0 b-buy"
v-if="show.bugStyle == 'custom'"
@tap.stop="buy"
>
<text>{{ show.bugTxt }}</text>
</view>
<view
class="shrink0 c-buy"
v-else-if="show.bugStyle == 'custom2'"
@tap.stop="buy"
>
<text>{{ show.bugTxt }}</text>
</view>
<view
class="shrink0 d-buy"
v-else-if="show.bugStyle == 'shop3'"
@tap.stop="buy"
>
<view class="cart-circle">
<uni-icons
type="cart"
:size="imgArg == 'big' ? 22 : 18"
color="#ffffff"
/>
<text v-if="cartNum > 0" class="count">{{ cartNum }}</text>
</view>
</view>
<view class="shrink0 a-buy" v-else @tap.stop="buy">
<view class="text" v-if="show.bugStyle == 'shop'" @tap.stop="buy">
<uni-icons
type="cart-filled"
:size="imgArg == 'big' ? 40 : 34"
color="#ff4444"
/>
<text v-if="cartNum > 0" class="cart-count">{{ cartNum }}</text>
</view>
<view
class="text"
v-else-if="show.bugStyle == 'shop2'"
@tap.stop="buy"
>
<uni-icons
type="cart"
:size="imgArg == 'big' ? 40 : 34"
color="#ff4444"
/>
<text v-if="cartNum > 0" class="cart-count">{{ cartNum }}</text>
</view>
<view
class="text"
v-else-if="show.bugStyle == 'plus'"
@tap.stop="buy"
>
<uni-icons
type="plus-filled"
:size="imgArg == 'big' ? 40 : 34"
color="#ff4444"
/>
<text v-if="cartNum > 0" class="cart-count">{{ cartNum }}</text>
</view>
<view
class="text"
v-else-if="show.bugStyle == 'plus2'"
@tap.stop="buy"
>
<uni-icons
type="plus"
:size="imgArg == 'big' ? 40 : 34"
color="#ff4444"
/>
<text v-if="cartNum > 0" class="cart-count">{{ cartNum }}</text>
</view>
</view>
</template>
</view>
<view class="none-h" v-else></view>
<!-- 返佣设定[佣金设定先用tag形式] -->
<view class="good-reward dec-truncate" v-if="rewardShow">
<template v-if="predictReward">预计返¥{{ predictReward }}</template>
</view>
<!-- 所属店铺 -->
<view v-if="shopNameShow" @tap.stop="goShop">
<view class="shop-name dec-row-flex j-between">
<view class="text shrink1 dec-truncate">{{
good.shopName || "所属店铺"
}}</view>
<uni-icons
class="shrink0"
type="right"
:size="imgArg == 'big' ? 16 : 14"
color="#999999"
/>
</view>
</view>
<view class="none-h" v-else-if="imgArg == 'big'"></view>
</view>
</template>
<script>
export default {
inject: ["decImgDomain", "decAxios"],
props: {
moudle: {
type: String,
default: "goodList",
},
good: {
type: Object,
default: () => {
return {};
},
},
show: {
type: Object,
default: () => {
return {};
},
},
count: {
type: Number,
default: 0,
},
imgArg: {
type: String,
default: "", // big middle small
},
imgH: {
type: String,
default: "",
},
},
data() {
return {
cartNum: 0,
postName: {
1: "保税仓",
2: "香港直邮",
3: "海外直邮",
},
};
},
watch: {
count(val, val2) {
if (val != val2) this.cartNum = val || 0;
},
},
created() {
this.cartNum = this.count || 0;
},
computed: {
className() {
let str = [];
if (this.imgArg) str.push(this.imgArg);
if (this.show.radius) str.push("radius");
return str;
},
titleClass() {
if (!this.imgH || ["one", "big"].includes(this.imgArg)) {
return "dec-truncate2";
} else {
return "dec-truncate";
}
},
hasShop() {
const hasShop = this.show.price || this.show.origin;
const hasShop2 = this.show.bug && this.imgArg != "small";
return hasShop || hasShop2;
},
opriceShow() {
if (this.show.origin && this.good.smarketPrice) {
return this.good.smarketPrice > this.good.salePrice;
}
return false;
},
predictReward() {
let val = this.good.predictReward || 0;
val = parseInt(val * 100);
if (val > 0) {
val = `${val / 100}`;
const arr = val.split(".");
if (arr[1]) {
val = arr[1].length == 1 ? `${arr[0]}.${arr[1]}0` : val;
} else {
val = `${val}.00`;
}
} else {
val = "";
}
return val;
},
rewardShow() {
const flag1 = this.imgArg != "big" && this.show.reward;
const flag2 = !!this.imgH || !!this.predictReward;
return flag1 && flag2;
},
postTypeShow() {
const flag1 = this.show.postType;
const flag2 = !!this.imgH || !!this.good.postType;
return flag1 && flag2;
},
tagRewardShow() {
const flag1 = this.imgArg == "big" && this.show.reward;
const flag2 = !!this.imgH || !!this.predictReward;
return flag1 && flag2;
},
shopNameShow() {
const flag1 = this.show.shopName;
const flag2 = !!this.imgH || !!this.good.shopName;
return flag1 && flag2;
},
},
methods: {
go() {
this.decAxios.decEventHandler(
{
moudle: this.moudle,
type: "detail",
desc: "跳商品详情页",
},
this.good,
null
);
},
buy() {
const that = this;
this.decAxios.decEventHandler(
{
moudle: this.moudle,
type: "buy",
desc: "购买商品",
},
this.good,
(obj) => {
that.cartNum = obj[that.good.id] || 0;
that.$emit("refreshBuyNum", obj);
}
);
},
goShop() {
this.decAxios.decEventHandler(
{
moudle: this.moudle,
type: "shop",
desc: "跳所属店铺",
},
this.good,
null
);
},
},
};
</script>
<template>
<view class="item-wrap" v-if="goods && goods.length > 0">
<!-- 商品为:字下图img -->
<template v-if="arg === 'img'">
<view class="img-wrap" v-for="(product, i) in goods" :key="i">
<good-img :good="product" :show="show" :simple="false" imgArg="big" />
</view>
</template>
<!-- 商品为: 拼图join-左右 img['4']??-->
<template v-else-if="arg === 'join'">
<view class="join-wrap" v-for="(item, j) in goods" :key="j">
<view class="big-wrap">
<good-img :good="item.big" :show="show" :imgH="img.h2" />
</view>
<view class="small-wrap">
<view class="item">
<good-img :good="item.small[0]" :show="show" imgArg="small" />
</view>
<view class="item">
<good-img :good="item.small[1]" :show="show" imgArg="small" />
</view>
</view>
</view>
</template>
<!-- 商品为: 组图concat-上下-->
<template v-else-if="arg === 'concat'">
<view class="concat-wrap" v-for="(item, k) in goods" :key="k">
<view class="big-wrap">
<good-short
@refreshBuyNum="refreshBuyNum"
:good="item.big"
:show="show"
imgArg="big"
:imgH="img.h1"
/>
</view>
<view class="small-wrap">
<view class="item">
<good-img :good="item.small[0]" :show="show" :imgH="img.h2" />
</view>
<view class="item">
<good-img :good="item.small[1]" :show="show" :imgH="img.h2" />
</view>
</view>
</view>
</template>
<!-- 商品为:列表list-x -->
<template v-else-if="'list,list-x'.indexOf(arg) > -1">
<view class="list-wrap" v-for="(product, l) in goods" :key="l">
<good-long
@refreshBuyNum="refreshBuyNum"
:good="product"
:count="cartListMap[product.id] || 0"
:show="show"
imgArg=""
:imgW="img.w40"
/>
</view>
</template>
<!-- 商品为:滚两图scroll-two -->
<template v-else-if="'scroll-two' == arg">
<swiper
class="swiper-scroll"
:indicator-dots="false"
:style="{ height: scrollH }"
>
<swiper-item v-for="(product, m) in goods" :key="m">
<view class="swiper-wrap">
<view v-for="(item, h) in product" :key="h" class="swiper-item">
<good-img :good="item" :show="show" :imgH="img.h2" />
</view>
</view>
</swiper-item>
</swiper>
</template>
<!-- 商品为:滚三图scroll-three -->
<template v-else-if="'scroll-three' == arg">
<swiper
class="swiper-scroll"
:indicator-dots="false"
:style="{ height: scrollH }"
>
<swiper-item v-for="(product, n) in goods" :key="n">
<view class="swiper-wrap">
<view
v-for="(item, r) in product"
:key="r"
class="swiper-item three"
>
<good-short
:moudle="moudle"
:good="item"
:show="show"
:imgH="img.h3"
imgArg="small"
/>
</view>
</view>
</swiper-item>
</swiper>
</template>
<!-- 商品为:三图,二图,大图 -->
<template v-else-if="'three' == arg">
<view v-for="(product, o) in goods" :key="o" class="item">
<good-short
:moudle="moudle"
:good="product"
:show="show"
:imgH="img.h3"
imgArg="small"
/>
</view>
</template>
<template v-else-if="'double,two'.indexOf(arg) > -1">
<view v-for="(product, p) in goods" :key="p" class="item">
<good-short
@refreshBuyNum="refreshBuyNum"
:moudle="moudle"
:count="cartListMap[product.id] || 0"
:good="product"
:show="show"
:imgH="img.h2"
/>
</view>
</template>
<template v-else>
<view v-for="(product, q) in goods" :key="q" class="item">
<good-short
@refreshBuyNum="refreshBuyNum"
:moudle="moudle"
:count="cartListMap[product.id] || 0"
:good="product"
:show="show"
:imgH="img.h1"
imgArg="big"
/>
</view>
</template>
</view>
</template>
<script>
// 设置列表
import goodShort from "./goodShort.vue";
import goodLong from "./goodLong.vue";
import goodImg from "./goodImg.vue";
export default {
inject: ["decAxios"],
components: {
goodShort,
goodLong,
goodImg,
},
props: {
moudle: {
type: String,
default: "goodList",
},
arg: {
type: String,
default: "",
},
groupKey: {
type: String,
default: "left",
},
goodKey: {
type: String,
default: "",
},
},
data() {
return {
goodIds: [],
cartListMap: {}, //购物车列表对象
goods: [],
show: {},
img: {},
};
},
created() {
const dataKey = `${this.groupKey}-${this.goodKey}`;
let parent = {};
// #ifdef H5
parent = this.$parent.$parent.$parent;
if (!parent.allGoods) parent = parent.$parent;
if (!parent.allGoods) parent = parent.$parent;
if (!parent.allGoods) parent = parent.$parent;
// #endif
// #ifndef H5
parent = this.$parent;
// #endif
if (parent.allGoods) {
this.goods = parent.allGoods[dataKey];
if (this.goods && this.goods.length > 0) {
this.img = parent.img;
this.show = parent.show;
if (!!this.show.bug) {
//处理购买按钮的数量显示
this.refreshBuyNum();
//监听购物车局部刷新事件
const decPageType = this.decAxios.getAppMemberData("decPageType");
const emitKey = `refreshAppCartEvent${decPageType || "1"}`;
uni.$on(emitKey, (e) => {
this.refreshBuyNum(e);
}); //全局购物车刷新事件
}
}
}
},
computed: {
scrollH() {
if (this.arg == "scroll-two") {
const h = parseInt((this.img.h2 || "").replace("px", "")) + 14;
return h + "px";
} else if (this.arg == "scroll-three") {
const h = parseInt((this.img.h3 || "").replace("px", "")) + 14;
return h + "px";
}
return "";
},
},
watch: {
goodKey(val) {
if (val) {
const dataKey = `${this.groupKey}-${this.goodKey}`;
this.goods = this.$parent.allGoods[dataKey];
}
},
},
methods: {
refreshBuyNum(e) {
const obj = e || this.decAxios.getAppMemberData() || {}; //刷新购物车对象
this.cartListMap = obj; //刷新购物车对象
},
},
beforeDestroy() {
const decPageType = this.decAxios.getAppMemberData("decPageType");
const emitKey = `refreshAppCartEvent${decPageType || "1"}`;
uni.$off(emitKey);
},
};
</script>
.dec-img-good {
position: relative;
overflow: hidden;
background-color: #ffffff;
font-size: 0 !important;
&.small {
height: 100%;
}
&.radius {
border-radius: 10 * @rpx;
}
image {
min-height: 40 * @rpx;
}
.good-img {
width: 100%;
height: 100%;
}
.good-info {
width: 100%;
position: absolute;
bottom: 0;
left: 0;
box-sizing: border-box;
padding: 6 * @rpx 10 * @rpx;
background: rgba(#000, 0.2);
&.black {
background: rgba(#fff, 0.3);
}
}
.good-title {
width: 100%;
font-size: @font-base;
color: #ffffff;
word-break: break-all;
&.black {
color: @color-head;
}
}
&.big .good-title {
font-size: @font-big;
}
&.small .good-title {
font-size: @font-sub;
line-height: 1.2;
}
.price-wrap {
.dot {
font-size: @font-base;
padding: 4 * @rpx 0;
padding-right: 2 * @rpx;
color: @color-theme;
line-height: 1;
}
.sale {
display: inline-block;
color: @color-theme;
font-size: @font-big;
padding: 4 * @rpx 0;
padding-right: 6 * @rpx;
line-height: 1;
}
.origin {
color: @color-text2;
font-size: @font-sub;
text-decoration: line-through;
padding: 4 * @rpx 0;
padding-right: 4 * @rpx;
line-height: 1;
}
}
&.big .sale {
font-size: 22 * @rpx;
}
&.small .sale {
font-size: @font-sub;
}
.good-reward {
display: inline-block;
color: @color-theme2;
font-size: @font-big;
}
}
.dec-long-good {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
overflow: hidden;
box-shadow: @shadow-good;
&.radius {
border-top-right-radius: 12 * @rpx;
border-bottom-right-radius: 12 * @rpx;
border-bottom-left-radius: 12 * @rpx;
.good-img {
overflow: hidden;
border-top-left-radius: 12 * @rpx;
}
}
.good-img {
margin: 0;
width: 40%;
font-size: 0;
flex-shrink: 0;
position: relative;
font-size: 0;
.img {
width: 100%;
object-fit: contain;
}
.mark {
position: absolute;
top: 0;
left: 0;
background-repeat: no-repeat;
background-position: top left;
background-size: 100% auto;
background-image: url("https://cdn.lirimall.com//lirigo/filetempImage/mark-hot1_1662036462380.png");
&.hot1 {
width: 72 * @rpx;
height: 60 * @rpx;
background-size: 72 * @rpx auto;
}
&.hot2 {
top: -6px;
left: -8px;
width: 60 * @rpx;
height: 60 * @rpx;
background-image: url("https://cdn.lirimall.com//lirigo/filetempImage/mark-hot2_1662041742069.png");
}
&.hot3 {
width: 50 * @rpx;
height: 50 * @rpx;
background-image: url("https://cdn.lirimall.com//lirigo/filetempImage/mark-hot3_1662041773402.png");
}
&.new1 {
width: 50 * @rpx;
height: 50 * @rpx;
background-color: transparent;
background-image: url("https://cdn.lirimall.com//lirigo/filetempImage/mark-new1_1662036530753.png");
}
&.new2 {
width: 42 * @rpx;
height: 42 * @rpx;
background-image: url("https://cdn.lirimall.com//lirigo/filetempImage/mark-new2_1662041796945.png");
}
&.new3 {
width: 52 * @rpx;
height: 42 * @rpx;
background-image: url("https://cdn.lirimall.com//lirigo/filetempImage/mark-new3_1662041838785.png");
}
&.new4 {
width: 42 * @rpx;
height: 42 * @rpx;
background-image: url("https://cdn.lirimall.com//lirigo/filetempImage/mark-new4_1662041851913.png");
}
}
}
.good-info {
width: 60%;
flex-shrink: 2;
position: relative;
background: #ffffff;
}
.good-intro {
padding: 10 * @rpx 10 * @rpx 0;
}
.good-title {
font-size: @font-middle;
color: @color-head;
}
.good-desc {
color: @color-text3;
font-size: @font-sub;
}
.price-wrap {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: 6 * @rpx 0;
box-sizing: border-box;
.dot {
font-size: @font-base;
padding: 10 * @rpx 0;
padding-left: 10 * @rpx;
padding-right: 2 * @rpx;
color: @color-theme;
line-height: 1;
}
.sale {
display: inline-block;
color: @color-theme;
font-size: 22 * @rpx;
padding: 12 * @rpx 0 8 * @rpx;
padding-right: 6 * @rpx;
line-height: 1;
}
.origin {
color: @color-text2;
font-size: @font-sub;
text-decoration: line-through;
padding: 10 * @rpx 0;
padding-right: 4 * @rpx;
line-height: 1;
}
.a-buy {
display: flex;
align-items: center;
justify-content: center;
width: 52 * @rpx;
height: 40 * @rpx;
}
.b-buy {
padding: 2 * @rpx 10 * @rpx;
text {
display: inline-block;
font-size: @font-base;
padding: 0 12 * @rpx;
height: 30 * @rpx;
line-height: 30 * @rpx;
border-radius: 15 * @rpx;
background: @color-theme;
color: #ffffff;
text-align: center;
}
}
.c-buy {
padding: 2 * @rpx 10 * @rpx;
text {
display: inline-block;
font-size: @font-base;
padding: 0 12 * @rpx;
height: 30 * @rpx;
line-height: 30 * @rpx;
border-radius: 15 * @rpx;
border: 1 * @rpx solid @color-theme;
color: @color-theme;
text-align: center;
}
}
.d-buy {
width: 88rpx;
height: 64rpx;
padding: 8rpx 20rpx;
box-sizing: border-box;
> view {
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
background: red;
box-sizing: border-box;
border-radius: 50%;
position: relative;
margin-right: 14rpx;
.count {
font-size: 20rpx;
height: 24rpx;
min-width: 24rpx;
border-radius: 12rpx;
border: 2rpx solid red;
position: absolute;
top: -8rpx;
right: -8rpx;
display: flex;
align-items: center;
justify-content: center;
color: red;
background: #ffffff;
}
}
}
}
.shop-name {
display: inline-block;
padding: 0 6 * @rpx;
background: rgba(@color-theme2, 0.2);
color: @color-theme2;
font-size: @font-sub;
margin-left: 4 * @rpx;
border-radius: 4 * @rpx;
margin-top: 6 * @rpx;
vertical-align: middle;
}
.good-reward {
display: inline-block;
padding: 0 6 * @rpx;
background: rgba(@color-theme2, 0.2);
color: @color-theme2;
font-size: @font-sub;
margin-left: 4 * @rpx;
border-radius: 4 * @rpx;
margin-top: 6 * @rpx;
vertical-align: middle;
}
}
.dec-box-good {
width: 100%;
background-color: #ffffff;
box-shadow: 0 0 6 * @rpx 2 * @rpx rgba(#000, 0.06);
overflow: hidden;
&.radius {
border-radius: 10 * @rpx;
}
//图片默认固定高度有利于加载的时候没有那么难看
image {
width: 100%;
height: 172 * @rpx;
}
&.big image {
height: 240 * @rpx;
}
&.small image {
height: 111 * @rpx;
}
.good-img {
width: 100%;
margin: 0;
font-size: 0;
overflow: hidden;
position: relative;
.imgH {
width: 100%;
height: 100%;
}
.imgW {
width: 100%;
height: 100%;
}
.mark {
position: absolute;
top: 0;
left: 0;
background-repeat: no-repeat;
background-position: top left;
background-size: 100% auto;
background-image: url("https://cdn.lirimall.com//lirigo/filetempImage/mark-hot1_1662036462380.png");
&.hot1 {
width: 72 * @rpx;
height: 60 * @rpx;
background-size: 72 * @rpx auto;
}
&.hot2 {
top: -6px;
left: -8px;
width: 60 * @rpx;
height: 60 * @rpx;
background-image: url("https://cdn.lirimall.com//lirigo/filetempImage/mark-hot2_1662041742069.png");
}
&.hot3 {
width: 50 * @rpx;
height: 50 * @rpx;
background-image: url("https://cdn.lirimall.com//lirigo/filetempImage/mark-hot3_1662041773402.png");
}
&.new1 {
width: 50 * @rpx;
height: 50 * @rpx;
background-color: transparent;
background-image: url("https://cdn.lirimall.com//lirigo/filetempImage/mark-new1_1662036530753.png");
}
&.new2 {
width: 42 * @rpx;
height: 42 * @rpx;
background-image: url("https://cdn.lirimall.com//lirigo/filetempImage/mark-new2_1662041796945.png");
}
&.new3 {
width: 52 * @rpx;
height: 42 * @rpx;
background-image: url("https://cdn.lirimall.com//lirigo/filetempImage/mark-new3_1662041838785.png");
}
&.new4 {
width: 42 * @rpx;
height: 42 * @rpx;
background-image: url("https://cdn.lirimall.com//lirigo/filetempImage/mark-new4_1662041851913.png");
}
}
}
.good-info {
padding: 0 10 * @rpx;
}
.good-title {
display: block;
box-sizing: border-box;
font-size: @font-base;
word-break: break-all;
color: @color-head;
white-space: wrap;
padding-top: 10 * @rpx;
}
&.big .good-title {
font-size: @font-middle;
}
&.small .good-title {
font-size: @font-sub;
}
.good-desc {
display: block;
color: @color-text3;
font-size: @font-sub;
}
&.big .good-desc {
padding-top: 6 * @rpx;
font-size: @font-base;
}
.none-h {
height: 10 * @rpx;
}
.tag-wrap {
display: flex;
flex-wrap: nowrap;
padding: 0 10 * @rpx;
> view:first-child {
margin-left: 0;
}
}
.post-type {
flex-shrink: 0;
display: inline-block;
padding: 0 4 * @rpx;
border: 1 * @rpx solid #7502f7;
color: #7502f7;
font-size: @font-small;
border-radius: 4 * @rpx;
margin-top: 6 * @rpx;
vertical-align: middle;
margin-left: 4 * @rpx;
&.no-text {
padding: 0;
border-color: transparent;
margin-left: 0;
width: 0;
&::before {
content: "";
display: inline-block;
width: 0;
height: @font-small;
}
}
}
.discount-name {
display: inline-block;
padding-right: 4 * @rpx;
border: 1 * @rpx solid @color-theme2;
color: @color-theme2;
font-size: @font-small;
border-radius: 4 * @rpx;
margin-top: 6 * @rpx;
vertical-align: middle;
margin-left: 4 * @rpx;
&.no-text {
padding: 0;
border-color: transparent;
margin-left: 0;
width: 0;
&::before {
content: "";
display: inline-block;
width: 0;
height: @font-small;
}
}
.flag {
padding: 0 3 * @rpx;
background-color: @color-theme2;
color: #ffffff;
margin-right: 4 * @rpx;
}
}
.price-wrap {
.dot {
font-size: @font-base;
padding: 10 * @rpx 0;
padding-left: 10 * @rpx;
padding-right: 2 * @rpx;
color: @color-theme;
line-height: 1;
}
.sale {
display: inline-block;
color: @color-theme;
font-size: @font-middle;
padding: 10 * @rpx 0;
padding-right: 6 * @rpx;
line-height: 1;
}
.origin {
color: @color-text2;
font-size: @font-sub;
text-decoration: line-through;
padding: 10 * @rpx 0;
padding-right: 4 * @rpx;
line-height: 1;
}
.text {
position: relative;
}
.cart-count {
font-size: 20rpx;
height: 24rpx;
min-width: 24rpx;
border-radius: 12rpx;
border: 2rpx solid red;
position: absolute;
top: 0rpx;
right: -4rpx;
display: flex;
align-items: center;
justify-content: center;
color: red;
background: #ffffff;
}
.a-buy {
display: flex;
align-items: center;
justify-content: center;
width: 52 * @rpx;
height: 40 * @rpx;
}
.b-buy {
padding: 2 * @rpx 10 * @rpx;
text {
display: inline-block;
font-size: 14 * @rpx;
padding: 0 8 * @rpx;
height: 24 * @rpx;
line-height: 24 * @rpx;
border-radius: 12 * @rpx;
background: @color-theme;
color: #ffffff;
text-align: center;
}
}
.c-buy {
padding: 2 * @rpx 10 * @rpx;
text {
display: inline-block;
font-size: 12 * @rpx;
padding: 0 8 * @rpx;
height: 24 * @rpx;
line-height: 24 * @rpx;
border-radius: 12 * @rpx;
border: 1 * @rpx solid @color-theme;
color: @color-theme;
text-align: center;
}
}
.d-buy {
width: 88rpx;
height: 64rpx;
padding: 4rpx 20rpx 12rpx;
box-sizing: border-box;
> view {
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
background: red;
box-sizing: border-box;
border-radius: 50%;
position: relative;
margin-right: 14rpx;
.count {
font-size: 20rpx;
height: 24rpx;
min-width: 24rpx;
border-radius: 12rpx;
border: 2rpx solid red;
position: absolute;
top: -8rpx;
right: -8rpx;
display: flex;
align-items: center;
justify-content: center;
color: red;
background: #ffffff;
}
}
}
}
//特殊样式处理
&.big .price-wrap {
.sale {
font-size: 22 * @rpx;
}
.a-buy {
width: 62 * @rpx;
height: 40 * @rpx;
}
.b-buy text,
.c-buy text {
padding: 0 16 * @rpx;
font-size: 16 * @rpx;
height: 32 * @rpx;
line-height: 32 * @rpx;
border-radius: 16 * @rpx;
}
.d-buy {
width: 88rpx;
height: 64rpx;
padding: 2rpx 28rpx 10rpx 8rpx;
}
}
.shop-name {
align-items: flex-start;
padding: 0 10 * @rpx 10 * @rpx;
.text {
display: block;
color: @color-text3;
}
}
&.big .shop-name .text {
font-size: @font-base;
}
.good-reward {
padding: 0 10 * @rpx 6 * @rpx;
color: @color-theme2;
font-size: @font-base;
&::before {
content: "";
display: inline-block;
width: 0;
height: @font-base;
}
}
&.small .good-reward {
padding: 0 6 * @rpx 6 * @rpx;
font-size: @font-sub;
}
}
// 商品样式
// 列表:list-x 字下图:img 拼图:join 组图:concat
// 大图:big 双图:double 三图:three
// 滚二图:scroll-two 滚三图:scroll-three
@import "./goodImg.less";
@import "./goodLong.less";
@import "./goodShort.less";
.dec-goodList {
.scroll-y {
height: 100vh;
}
.group-wrap {
width: 100%;
display: flex;
flex-wrap: nowrap;
padding: 0 @space2;
box-sizing: border-box;
.group {
width: 50%;
padding: 0 @space2;
box-sizing: border-box;
}
}
.one-group .img {
height: 240 * @rpx;
}
.two-group .img {
height: 172 * @rpx;
}
.three-group .img {
height: 110 * @rpx;
}
.item-wrap {
width: 100%;
> .item {
padding: @lacuna2 0;
}
}
.img-wrap {
padding: @lacuna2 0;
}
.list-wrap {
padding: @lacuna2 0;
}
.join-wrap {
position: relative;
.big-wrap {
width: 50%;
padding: @lacuna2 0;
padding-right: @space2;
box-sizing: border-box;
}
.small-wrap {
position: absolute;
top: 0;
right: 0;
width: 50%;
height: 100%;
padding: @lacuna2 0;
padding-left: @space2;
box-sizing: border-box;
}
.item {
height: 50%;
overflow: hidden;
box-sizing: border-box;
&:first-child {
padding-bottom: @lacuna2;
}
&:last-child {
padding-top: @lacuna2;
}
}
.dec-good-i.small {
height: 100%;
width: 100%;
}
}
.concat-wrap {
.big-wrap {
width: 100%;
padding: @lacuna2 0;
box-sizing: border-box;
}
.small-wrap {
display: flex;
flex-wrap: nowrap;
flex-direction: row;
padding: @lacuna2 0;
}
.item {
width: 50%;
box-sizing: border-box;
&:first-child {
padding-right: @lacuna2;
}
&:last-child {
padding-left: @lacuna2;
}
}
}
.swiper-scroll {
margin: 0 -@space2;
}
.swiper-wrap {
width: 100%;
display: flex;
flex-wrap: nowrap;
flex-direction: row;
}
.swiper-item {
width: 50%;
box-sizing: border-box;
padding: @lacuna2 @space2;
&.three {
width: 33.33%;
}
}
}
<template>
<view class="dec-goodSpecial" :style="className" v-if="bgImg" @tap="go">
<image class="img" mode="widthFix" :src="bgImg" />
</view>
</template>
<script>
// 设置分组
export default {
inject: ["decAxios", "decImgDomain"],
props: {
tab: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
bgImg: "",
};
},
computed: {
className() {
const arg = this.tab.arg;
let arr = [];
if (arg.space) arr.push(`margin: 0 ${arg.space}px`);
if (arg.radius) arr.push(`borderRadius: ${arg.radius}px`);
if (arg.bgColor && arg.bgColor != "transparent")
arr.push(`background-color: ${arg.bgColor}`);
if (arg.bgSize) arr.push(`padding: 0 ${50 - arg.bgSize * 0.5}%`);
return arr.join(";");
},
},
created() {
const arg = this.tab.arg;
const api = this.decAxios.getGoodSpecialData;
const select = arg.id,
that = this;
if (select.id) {
api({ id: select.id }).then(({ code, result }) => {
that.bgImg = "";
if (code == 200) that.bgImg = that.decImgDomain(result.picture);
});
} else {
this.bgImg = "";
}
},
methods: {
go() {
this.decAxios.decEventHandler(
{
moudle: "goodSpecial",
type: "detail",
desc: "跳专区商品页",
},
this.tab.arg.id,
null
);
},
},
};
</script>
.dec-goodSpecial {
overflow: hidden;
font-size: 0 !important;
.img {
width: 100%;
}
}
<template>
<view class="dec-img-block">
<image
class="img-block"
mode="widthFix"
v-if="img"
:src="img"
:show-menu-by-longpress="tab.type == 'imageBlock'"
/>
<view class="img-block img-default" v-else>自定义图片区域</view>
</view>
</template>
<script>
export default {
inject: ["decImgDomain"],
props: {
tab: {
type: Object,
default: () => {
return {};
},
},
},
data() {
return {
img: "",
};
},
created() {
const img = this.tab.arg && this.tab.arg.img;
console.log(this.tab, "tab");
this.img = this.decImgDomain(img || "");
},
};
</script>
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment