提交 7d5501b6 编写于 作者: S songchenglin3

Merge branch 'next' of https://github.com/jdf2e/nutui into next

......@@ -137,6 +137,15 @@ module.exports = {
show: true,
desc: '较长页面快捷回到顶部',
author: 'liqiong43'
},
{
name: 'Toast',
sort: '1',
cName: '吐司',
type: 'component',
show: true,
desc: '轻提示',
author: 'undo'
}
]
},
......@@ -265,6 +274,16 @@ module.exports = {
sort: 11,
show: false,
author: 'Ymm0008'
},
{
version: '3.0.0',
name: 'OverLay',
type: 'component',
cName: '遮罩层',
desc: '创建一个遮罩层,通常用于阻止用户进行其他操作',
sort: 14,
show: true,
author: 'szg2008'
}
]
},
......
<script lang="ts">
import { h, PropType, computed, toRefs } from 'vue';
import { h, PropType, computed } from 'vue';
import { createComponent } from '@/utils/create';
const { componentName, create } = createComponent('icon');
......@@ -14,34 +14,34 @@ export default create({
emits: ['click'],
setup(props, { emit, slots }) {
const { name, size, classPrefix, color, tag } = toRefs(props);
const handleClick = (event: Event) => {
emit('click', event);
};
const isImage = computed(() => {
return name.value ? name.value.indexOf('/') !== -1 : false;
}).value;
const isImage = () => {
return props.name ? props.name.indexOf('/') !== -1 : false;
};
return () =>
h(
isImage ? 'img' : tag.value,
return () => {
const _isImage = isImage();
return h(
_isImage ? 'img' : props.tag,
{
class: isImage
class: _isImage
? `${componentName}__img`
: `${classPrefix.value} ${componentName}-${name.value}`,
: `${props.classPrefix} ${componentName}-${props.name}`,
style: {
color: color.value,
fontSize: size.value,
width: isImage ? size.value : '',
height: isImage ? size.value : ''
color: props.color,
fontSize: props.size,
width: _isImage ? props.size : '',
height: _isImage ? props.size : ''
},
onClick: handleClick,
src: isImage ? name.value : ''
src: _isImage ? props.name : ''
},
slots.default?.()
);
};
}
});
</script>
......
<template>
<div class="demo">
<h2>基础用法</h2>
<nut-cell>
<nut-button type="primary" @click="state.show = true"
>显示遮罩层</nut-button
>
<nut-overlay v-model:show="state.show" :z-index="2000"></nut-overlay>
</nut-cell>
<h2>嵌套内容</h2>
<nut-cell>
<nut-button type="success" @click="state.show2 = true"
>嵌套内容</nut-button
>
<nut-overlay v-model:show="state.show2" :z-index="2000">
<div class="wrapper">
<div class="content">这里是正文</div>
</div>
</nut-overlay>
</nut-cell>
</div>
</template>
<script lang="ts">
import { reactive } from 'vue';
import { createComponent } from '@/utils/create';
const { createDemo } = createComponent('overlay');
export default createDemo({
props: {},
setup() {
const state = reactive({
show: false,
show2: false
});
return {
state
};
}
});
</script>
<style lang="scss" scoped>
.wrapper {
display: flex;
height: 100%;
align-items: center;
justify-content: center;
.content {
display: flex;
width: 150px;
height: 150px;
background: #fff;
border-radius: 8px;
align-items: center;
justify-content: center;
color: red;
}
}
</style>
# overlay 组件
### 介绍
创建一个遮罩层,通常用于阻止用户进行其他操作
### 安装
```javascript
import { createApp } from 'vue';
import { OverLay } from '@nutui/nutui';
const app = createApp();
app.use(OverLay);
```
## 代码演示
### 基础用法
```html
<nut-overlay v-model:show="state.show" :z-index="2000"></nut-overlay>
```
### 嵌套内容
```html
<nut-overlay v-model:show="state.show2" :z-index="2000">
<div class="wrapper">
<div class="content">这里是正文</div>
</div>
</nut-overlay>
```
## API
### Props
| 参数 | 说明 | 类型 | 默认值 |
| ---------------------- | ---------------- | -------------- | ------ |
| show | 当前组件是否显示 | Boolean | false |
| z-index | 遮罩层级 | String、Number | 2000 |
| duration | 动画时长,单位秒 | String、Number | 0.3 |
| overlay-class | 自定义遮罩类名 | String | - |
| overlay-style | 自定义遮罩样式 | CSSProperties | - |
| lock-scroll | 背景是否锁定 | Boolean | false |
| overlay | 是否显示遮罩 | Boolean | true |
| close-on-click-overlay | 是否点击遮罩关闭 | Boolean | true |
### Events
| 事件名 | 说明 | 回调参数 |
| ------ | ---------- | ------------ |
| click | 点击时触发 | event: Event |
.overlay-fade-enter-active {
animation: nut-fade-in;
}
.overlay-fade-leave-active {
animation: nut-fade-out;
}
.nut-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
}
@keyframes nut-fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes nut-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
<template>
<Transition name="popup-fade">
<Transition name="overlay-fade">
<view
@touchmove.stop="touchmove"
@click="onClick"
:style="{ animationDuration: `${duration}s`, ...overlayStyle, zIndex }"
v-show="show"
class="popup-bg nut-mask"
:class="overlayClass"
></view>
:class="classes"
>
<slot></slot>
</view>
</Transition>
</template>
<script lang="ts">
import { toRefs, CSSProperties, PropType, Transition } from 'vue';
import { CSSProperties, PropType, computed } from 'vue';
import { createComponent } from '@/utils/create';
const { componentName, create } = createComponent('popup-overlay');
const { componentName, create } = createComponent('overlay');
const overlayProps = {
show: {
type: Boolean,
......@@ -50,14 +52,32 @@ export { overlayProps };
export default create({
props: overlayProps,
emits: [],
setup(props) {
emits: ['click', 'update:show'],
setup(props, { emit }) {
const classes = computed(() => {
const prefixCls = componentName;
return {
[prefixCls]: true,
[props.overlayClass]: true
};
});
const touchmove = e => {
if (props.lockScroll) {
e.preventDefault();
}
};
return { touchmove };
const onClick = e => {
emit('click', e);
if (props.closeOnClickOverlay) {
emit('update:show', false);
}
};
return { classes, touchmove, onClick };
}
});
</script>
<style lang="scss">
@import 'index.scss';
</style>
......@@ -96,7 +96,7 @@
:style="{ height: '30%' }"
v-model:show="state.showRound"
></nut-popup>
<h2>组合弹框</h2>
<!-- <h2>组合弹框</h2> -->
<!-- <nut-cell title="组合弹框" is-link @click="state.showCombination = true"></nut-cell>
<nut-popup
id="combination"
......
......@@ -16,28 +16,108 @@ app.use(Popup);
## 代码演示
### 基础用法 1
### 基础用法
`Icon``name` 属性支持传入图标名称或图片链接。
`show` 控制显示/隐藏
```html
<nut-popup name="wifi"></nut-popup> <nut-popup name="mail"></nut-popup>
<nut-popup :style="{ padding: '30px' }" v-model:show="show">正文</nut-popup>
```
### 弹出位置
```html
<nut-popup
position="top"
v-model:show="show"
:style="{ height: '20% }"
></nut-popup>
<nut-popup
position="left"
v-model:show="show"
:style="{ height: '100%', width: '20%' }"
></nut-popup>
```
### 图标
```html
<nut-popup
position="bottom"
closeable
:style="{ height: '20%' }"
v-model:show="show"
></nut-popup>
<nut-popup
position="bottom"
closeable
close-icon-position="top-left"
:style="{ height: '20%' }"
v-model:show="show"
></nut-popup>
<nut-popup
position="bottom"
closeable
close-icon-position="top-left"
close-icon="heart"
:style="{ height: '20%' }"
v-model:show="show"
></nut-popup>
```
### 圆角弹框
```html
<nut-popup
position="bottom"
closeable
round
:style="{ height: '30%' }"
v-model:show="show"
></nut-popup>
```
### 指定挂载节点
```html
<nut-popup :style="{ padding: '30px' }" teleport="#app" v-model:show="show">app</nut-popup
```
## API
### Props
| 参数 | 说明 | 类型 | 默认值 |
| ------------ | -------------------------------- | ------ | ---------------- |
| name | 图标名称或图片链接 | String | - |
| color | 图标颜色 | String | - |
| size | 图标大小,如 `20px` `2em` `2rem` | String | - |
| class-prefix | 类名前缀,用于使用自定义图标 | String | `nutui-iconfont` |
| tag | HTML 标签 | String | `i` |
| 参数 | 说明 | 类型 | 默认值 |
| ---------------------- | ----------------------------------------------------------- | -------------- | ----------- |
| show | 当前组件是否显示 | Boolean | false |
| z-index | 遮罩层级 | String、Number | 2000 |
| duration | 动画时长,单位秒 | String、Number | 0.3 |
| overlay-class | 自定义遮罩类名 | String | - |
| overlay-style | 自定义遮罩样式 | CSSProperties | - |
| lock-scroll | 背景是否锁定 | Boolean | false |
| overlay | 是否显示遮罩 | Boolean | true |
| close-on-click-overlay | 是否点击遮罩关闭 | Boolean | true |
| position | 弹出位置(top,bottom,left,right,center) | String | "center" |
| transition | 动画名 | String | - |
| style | 自定义弹框样式 | CSSProperties | - |
| closeable | 是否显示关闭按钮 | Boolean | true |
| close-icon-position | 关闭按钮位置(top-left,top-right,bottom-left,bottom-right) | String | "top-right" |
| close-icon | 自定义 Icon | String | "close" |
| destroy-on-close | 组件销毁后是否关闭 | Boolean | true |
| round | 是否显示圆角 | Boolean | false |
| teleport | 指定挂载节点 | String | "body" |
### Events
| 事件名 | 说明 | 回调参数 |
| ------ | -------------- | ------------ |
| click | 点击图标时触发 | event: Event |
| 事件名 | 说明 | 回调参数 |
| ---------------- | ---------------------- | ------------ |
| click | 点击弹框时触发 | event: Event |
| click-close-icon | 点击关闭图标时触发 | event: Event |
| open | 打开弹框时触发 | - |
| close | 关闭弹框时触发 | - |
| opend | 遮罩打开动画结束时触发 | event: Event |
| closed | 遮罩关闭动画结束时触发 | event: Event |
| click-overlay | 点击遮罩触发 | event: Event |
.popup-fade-enter-active {
animation: nut-fade-in;
}
.popup-fade-leave-active {
animation: nut-fade-out;
}
.popup-slide {
&-center-enter-active {
animation: nut-fade-in;
......@@ -79,7 +71,7 @@
}
}
.popup-box {
.nut-popup {
position: fixed;
max-height: 100%;
overflow-y: auto;
......@@ -145,12 +137,3 @@
}
}
}
.popup-bg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
}
<template>
<Teleport :to="teleport">
<nut-popup-overlay
<nut-overlay
:show="show && overlay"
v-if="state.overLayCount === 1"
:class="overlayClass"
:style="overlayStyle"
:zIndex="state.zIndex"
......@@ -14,13 +13,7 @@
@after-enter="onOpened"
@after-leave="onClosed"
>
<view
v-show="show"
class="popup-box"
:class="[`popup-${position}`, { round }]"
:style="popStyle"
@click="onClick"
>
<view v-show="show" :class="classes" :style="popStyle" @click="onClick">
<slot v-if="state.showSlot"></slot>
<nut-icon
v-if="closeable"
......@@ -49,7 +42,7 @@ import {
CSSProperties
} from 'vue';
import { useLockScroll } from './use-lock-scroll';
import Overlay, { overlayProps } from './overlay/index.vue';
import { overlayProps } from './../overlay/index.vue';
import { createComponent } from '@/utils/create';
const { componentName, create } = createComponent('popup');
......@@ -92,7 +85,7 @@ const popupProps = {
destroyOnClose: {
type: Boolean,
default: false
default: true
},
teleport: {
......@@ -107,9 +100,6 @@ const popupProps = {
};
export default create({
Component: {
'nut-popup-overlay': Overlay
},
props: {
...overlayProps,
...popupProps
......@@ -139,6 +129,15 @@ export default create({
const [lockScroll, unlockScroll] = useLockScroll(() => props.lockScroll);
const classes = computed(() => {
const prefixCls = componentName;
return {
[prefixCls]: true,
['round']: props.round,
[`popup-${props.position}`]: true
};
});
const popStyle = computed(() => {
return {
zIndex: state.zIndex,
......@@ -262,10 +261,8 @@ export default create({
onClosed,
state,
popStyle,
componentName
classes
};
// return renderOverlay();
}
});
</script>
......
import { createApp, h } from 'vue';
import overlayComponent from './overlay.vue';
let modalStack = [];
let _zIndex = 2000;
let overlay;
function mountd(Component, data) {
const instance = createApp(Component);
instance
.component(Component.name, {
render() {
return h(Component.name, ...data, this.$slots.default());
}
})
.mount();
console.log(instance);
return instance;
}
const overlayManager = {
lockCount: 0,
get topStack() {
return modalStack[modalStack.length - 1];
},
getZIndex(id) {
if (!id) return ++_zIndex;
const overlay = modalStack.find(res => {
return res.config.id === id;
});
if (overlay) {
return overlay.config.zIndex;
} else {
return ++_zIndex;
}
},
updateOverlay() {
const { clickHandle, topStack } = overlayManager;
if (!overlay) {
overlay = mountd(overlayComponent, {
nativeOn: {
click: clickHandle
}
});
}
console.log(topStack.vm);
if (topStack) {
const { vm, config } = topStack;
const el = vm.ctx.$el;
el && el.parentNode && el.parentNode.nodeType !== 11
? el.parentNode.appendChild(overlay.$el)
: document.body.appendChild(overlay.$el);
Object.assign(overlay, config, {
value: true
});
} else {
overlay.value = false;
}
},
//打开遮罩层
openModal(vm, config) {
const { zIndex, duration, overlayClass, overlayStyle, id } = config;
modalStack.push({
vm,
config: {
id,
zIndex,
duration,
overlayClass,
overlayStyle
}
});
overlayManager.updateOverlay();
},
clickHandle() {
const { topStack } = overlayManager;
//防止多次点击
if (modalStack.length && topStack.vm.closeOnClickOverlay) {
topStack.vm.$emit('click-overlay');
topStack.vm.close();
}
},
closeOverlay(vm) {
if (modalStack.length) {
if (overlayManager.topStack.vm === vm) {
modalStack.pop();
overlayManager.updateOverlay();
} else {
modalStack = modalStack.filter(item => item.vm !== vm);
}
}
}
};
const overlayProps = {
value: {
type: Boolean,
default: false
},
overlay: {
type: Boolean,
default: true
},
lockScroll: {
type: Boolean,
default: true
},
duration: {
type: Number,
default: 0.3
},
closeOnClickOverlay: {
type: Boolean,
default: true
},
overlayClass: {
type: String,
default: ''
},
overlayStyle: {
type: Object,
default: function() {
return null;
}
},
zIndex: {
type: Number
}
};
export { overlayManager, overlayProps };
......@@ -52,8 +52,10 @@ export default createDemo({
Toast.warn(msg);
};
const loadingToast = msg => {
Toast.loading(msg, { duration: 0 });
setTimeout(Toast.hide, 3000);
Toast.loading(msg, { duration: 0, id: 'test' });
setTimeout(() => {
Toast.success('加载完成', { id: 'test', duration: 2000 });
}, 2000);
};
return {
textToast,
......
......@@ -2,154 +2,75 @@
轻提示。
## 基本用法
文字提示
```javascript
export default {
mounted() {
this.$toast.text('提示信息');
}
}
```
### 介绍
成功提示
用于轻提示。
```javascript
export default {
mounted() {
this.$toast.success('操作成功!');
}
}
### 安装
``` javascript
import { createApp } from 'vue';
import { Toast } from '@nutui/nutui';
const app = createApp();
app.use(Toast);
```
失败提示
## 代码演示
### 基本用法
文字提示
```javascript
export default {
mounted() {
this.$toast.fail('操作失败!');
}
}
Toast.text(msg);
```
警告提示
成功提示
```javascript
export default {
mounted() {
this.$toast.warn('确定删除?');
}
}
Toast.success(msg);
```
## 加载提示
失败提示
```javascript
// 带文案,显示透明遮罩层(默认),自动消失
this.$toast.loading('加载中...',{
duration:3000
});
//带文案,显示半透明遮罩层,自动消失,点击遮罩层后消失
this.$toast.loading('加载中...',{
duration:3000,
coverColor: "rgba(0,0,0,0.5)",
closeOnClickOverlay: true
});
//不会自动消失(默认),不带遮罩层
this.loading = this.$toast.loading({
cover: false
});
//手动关闭上面的Loading
this.loading.hide();
Toast.fail(msg);
```
## 自定义样式
警告提示
```javascript
//自定义背景颜色/透明度
this.$toast.text('自定义背景颜色/透明度',{
bgColor:'rgba(50, 50, 50, 0.9)'
});
//自定义class
this.$toast.text('自定义class',{
customClass:'my-class'
});
//自定义Icon
this.$toast.text('自定义Icon',{
icon:"https://img13.360buyimg.com/imagetools/jfs/t1/98294/28/14470/22072/5e65ba08E865683aa/ded7441bdd098511.png"
});
Toast.warn(msg);
```
## 共享实例
如果不设置id,多个Toast将默认拥有相同的id,**它们将共享一个实例**(loading类型与其他类型实例不共享),新的内容和设置将取代旧的,多个Toast不能同时出现。如果不需要共享实例,可以给其设置id。
### 动态更新
```javascript
//二者id不同,不会共享一个实例
this.$toast.success(msg,{
id:123
});
this.$toast.text(msg,{
id:321,
duration:4000
});
Toast.loading(msg, { duration: 0, id: 'test' });
setTimeout(() => {
Toast.success('加载完成', { id: 'test', duration: 2000 });
}, 2000);
```
## 支持在JS模块中导入使用
##¥ 支持在JS模块中导入使用
```javascript
import { Toast } from "@nutui/nutui";
Toast.text('在js模块中使用');
// 返回实例,可以手动调用实例中的hide方法关闭提示
const toast = Toast.loading('在js模块中使用');
toast.hide();
```
## 修改默认配置
通过**Toast.setDefaultOptions**函数可以全局修改 Toast 的默认配置,**值得注意的是,loading无法支持默认配置的修改和重置**
```js
// 更改所有Toast展示时长设置为5000毫秒
Toast.setDefaultOptions({
duration: 5000,
coverColor: "rgba(0, 0, 0, 0.2)",
closeOnClickOverlay: true,
cover: true
});
// 重置所有 Toast 的默认配置
Toast.resetDefaultOptions();
// 更改所有文字提示默认设置
Toast.setDefaultOptions("text", {
size: "large",
cover: true,
coverColor: "rgba(0, 0, 0, 0.2)",
duration: 3000,
closeOnClickOverlay: true
});
// 重置 text Toast 的默认配置
Toast.resetDefaultOptions("text");
```
### API
| 方法名 | 说明 | 参数 | 返回值 |
| ------------------------- | ----------------------------------------------------------------------- | --------------- | ---------- |
| Toast.text | 展示文字提示 | options/message | toast 实例 |
| Toast.loading | 展示加载提示 | options/message | toast 实例 |
| Toast.success | 展示成功提示 | options/message | toast 实例 |
| Toast.fail | 展示失败提示 | options/message | toast 实例 |
| Toast.warn | 展示警告提示 | options/message | toast 实例 |
| Toast.hide | 关闭提示 | force:boolean | void |
| Toast.setDefaultOptions | 修改默认配置,对所有 Toast 生效<br>传入 type 可以修改指定类型的默认配置 | type/options | void |
| Toast.resetDefaultOptions | 重置默认配置,对所有 Toast 生效<br>传入 type 可以重置指定类型的默认配置 | type | void |
| Toast.loading | 展示加载提示 | options/message | toast 实例 |
## Options
......
......@@ -85,15 +85,15 @@
}
}
.toastfade-enter-active {
transition: opacity 0.1s;
.toast-fade-enter-active {
transition: opacity 0.3s;
}
.toastfade-leave-active {
.toast-fade-leave-active {
transition: opacity 0.3s;
}
.toastfade-enter,
.toastfade-leave-active {
.toast-fade-enter-from,
.toast-fade-leave-to {
opacity: 0;
}
<template>
<transition name="toastfade">
<Transition name="toast-fade" @after-leave="onAfterLeave">
<view
:id="id"
:class="toastBodyClass"
v-if="visible"
v-show="state.mounted"
:style="{
bottom: center ? 'auto' : bottom + 'px',
'background-color': coverColor
......@@ -23,21 +22,17 @@
<view class="nut-toast-text" v-html="msg"></view>
</view>
</view>
</transition>
</Transition>
</template>
<script>
import Icon from '../icon';
import { toRefs, reactive, computed, watch } from 'vue';
import { toRefs, toRef, reactive, computed, watch, onMounted } from 'vue';
import { createComponent } from '@/utils/create';
const { create } = createComponent('toast');
export default create({
props: {
id: String,
msg: String,
visible: {
type: Boolean,
default: false
},
duration: {
type: Number,
default: 2000
......@@ -89,31 +84,31 @@ export default create({
'nut-icon': Icon
},
setup(props) {
console.log('props', props);
let timer;
const state = reactive({
timer: null
mounted: false
});
onMounted(() => {
state.mounted = true;
});
const clearTimer = () => {
if (state.timer) {
clearTimeout(state.timer);
state.timer = null;
if (timer) {
clearTimeout(timer);
timer = null;
}
};
const hide = () => {
clearTimer();
props.unmount(props.id);
props.onClose && props.onClose();
state.mounted = false;
};
const show = () => {
clearTimer();
if (props.duration) {
state.timer = setTimeout(() => {
timer = setTimeout(() => {
hide();
}, props.duration);
}
};
const clickCover = () => {
console.log('click');
if (props.closeOnClickOverlay) {
hide();
}
......@@ -123,8 +118,16 @@ export default create({
show();
}
watch(
() => props.duration,
val => {
if (val) {
show();
}
}
);
const hasIcon = computed(() => {
console.log(props.type);
if (props.type !== 'text') {
return true;
} else {
......@@ -142,11 +145,20 @@ export default create({
'nut-toast-' + props.size
];
});
const onAfterLeave = () => {
clearTimer();
props.unmount(props.id);
props.onClose && props.onClose();
};
return {
state,
hide,
clickCover,
hasIcon,
toastBodyClass
toastBodyClass,
onAfterLeave
};
}
});
......
import { createVNode, render, App } from 'vue';
import { createVNode, defineComponent, render, App } from 'vue';
import VueToast from './index.vue';
const ToastConstructor = defineComponent(VueToast);
const defaultOptions = {
msg: '',
id: '',
visible: false,
duration: 2000, //显示时间(毫秒)
center: true,
type: 'text',
......@@ -22,33 +21,66 @@ const defaultOptions = {
closeOnClickOverlay: false
};
let currentOptions = {
...defaultOptions
let idsMap: string[] = [];
let optsMap: any[] = [];
const clearToast = (id?: string) => {
if (id) {
const container = document.getElementById(id);
optsMap = optsMap.filter(item => item.id !== id);
idsMap = idsMap.filter(item => item !== id);
if (container) {
document.body.removeChild(container);
}
} else {
idsMap.forEach(item => {
const container = document.getElementById(item);
if (container) {
document.body.removeChild(container);
}
});
optsMap = [];
idsMap = [];
}
};
const clearToast = (id = currentOptions.id) => {
const container = document.getElementById(id);
const updateToast = opts => {
const container = document.getElementById(opts.id);
if (container) {
document.body.removeChild(container);
const currentOpt = optsMap.find(item => item.id === opts.id);
if (currentOpt) {
opts = { ...defaultOptions, ...currentOpt, ...opts };
} else {
opts = { ...defaultOptions, ...opts };
}
const instance: any = createVNode(ToastConstructor, opts);
render(instance, container);
return instance.component.ctx;
}
};
const mountToast = opts => {
// checkExitToast();
opts = { ...defaultOptions, ...opts };
opts.visible = true;
opts.unmount = clearToast;
opts.id = new Date().getTime() + '';
console.log(opts);
currentOptions = { ...opts };
let _id;
// 如果是更新已有的toast
if (opts.id) {
_id = opts.id;
if (idsMap.find(item => item === opts.id)) {
return updateToast(opts);
}
} else {
_id = new Date().getTime() + '';
}
opts = { ...defaultOptions, ...opts };
opts.id = _id;
idsMap.push(opts.id);
optsMap.push(opts);
const container = document.createElement('div');
container.id = opts.id;
const vm = createVNode(VueToast, opts);
render(vm, container);
const instance: any = createVNode(ToastConstructor, opts);
render(instance, container);
document.body.appendChild(container);
console.log(vm);
return vm;
console.log(instance.component);
return instance.component.ctx;
};
const errorMsg = msg => {
......
......@@ -3,7 +3,7 @@ import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
import Index from './views/Index.vue';
import Resource from './views/Resource.vue';
import Main from './views/Main.vue';
import { HttpClient } from '../service/HttpClient';
const pagesRouter: Array<RouteRecordRaw> = [];
const files = require.context('@/packages', true, /doc\.md$/);
files.keys().forEach(component => {
......@@ -57,5 +57,10 @@ const router = createRouter({
}
}
});
router.afterEach((to, from) => {
new HttpClient().request('/user/saveVisitInfo', 'post', {
headers: '',
componentName: to.path.split('/')[1]
});
});
export default router;
......@@ -13,4 +13,11 @@ export class ArticleApiService {
getArticle() {
return this.httpClient.request('/article/list', 'get', {});
}
/**
* 保存用户访问数据
* @returns
*/
saveUserInfo(parmas) {
return this.httpClient.request('/user/saveVisitInfo', 'post', parmas);
}
}
// vue.config.js
const path = require('path');
//target: 'http://localhost:7004',
module.exports = {
productionSourceMap: process.env.NODE_ENV != 'production',
publicPath: './',
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册