李恒道 发表于 2021-11-21 22:59:55

[油猴脚本开发指南]SweetAlert2进阶

# 前言

我们之前已经学了SweetAlert2,这节课我们简单进行一下进阶的学习~

# 对话框重用

我们可以使用**Swal**.**mixin**来创建可重用的对话框



```javascript
const Toast = Swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
    toast.addEventListener('mouseenter', Swal.stopTimer)
    toast.addEventListener('mouseleave', Swal.resumeTimer)
}
})

Toast.fire({
icon: 'success',
title: 'Signed in successfully'
})
```

# 模板声明

我们也可以在html中写template模板然后在Swal传入来触发弹窗

使用这种声明方式,在SSR情况下比较方便(本人未尝试)

代码如下

```javascript
<template id="my-template">
<swal-title>
    Save changes to "Untitled 1" before closing?
</swal-title>
<swal-icon type="warning" color="red"></swal-icon>
<swal-button type="confirm">
    Save As
</swal-button>
<swal-button type="cancel">
    Cancel
</swal-button>
<swal-button type="deny">
    Close without Saving
</swal-button>
<swal-param name="allowEscapeKey" value="false" />
<swal-param
    name="customClass"
    value='{ "popup": "my-popup" }' />
</template>
```

然后我们使用

```javascript
Swal.fire({
template: '#my-template'
})
```

触发弹窗,其中template就是我们的template标签的id名

支持的模板参数如下,因为这个感觉较为小众,所以我就没有尝试了

```javascript
<swal-title>...</swal-title>
<swal-html>...</swal-html>
<swal-footer>...</swal-footer>
<swal-param name="..." value="..." />
<swal-button type="..." color="..." aria-label="...">...</swal-button>
<swal-image src="..." width="..." height="..." alt="..." />
<swal-icon type="..." color="...">...</swal-icon>
<swal-input type="..." label="..." placeholder="..." value="..." />
<swal-input-option value="...">...</swal-input-option>
```

# 声明式触发弹窗

我们也可以在html中通过声明属性的方式,然后触发弹窗,这时候我们需要使用的命令是**bindClickHandler**方法

例子如下

```javascript
<button data-swal-template="#my-template">
Trigger modal
</button>

<button data-swal-toast-template="#my-template">
Trigger toast
</button>
```

然后我们在js写

```javascript
Swal.bindClickHandler()

Swal.mixin({
toast: true,
}).bindClickHandler('data-swal-toast-template')
```

bindClickHandler如果不填写任何字符串,则默认为`'data-swal-template'`读取属性的字符串作为模板

而如果传入了,则读取相应属性的模板

这里我是通过源码大概看了一下才理解的,官方一笔带过,大家有兴趣也可以看一下,代码如下

```javascript
let bodyClickListenerAdded = false
const clickHandlers = {}

export function bindClickHandler (attr = 'data-swal-template') {
clickHandlers = this

if (!bodyClickListenerAdded) {
    document.body.addEventListener('click', bodyClickListener)
    bodyClickListenerAdded = true
}
}

const bodyClickListener = (event) => {
for (let el = event.target; el && el !== document; el = el.parentNode) {
    for (const attr in clickHandlers) {
      const template = el.getAttribute(attr)
      if (template) {
      clickHandlers.fire({ template })
      return
      }
    }
}
}

```


# 处理按钮的返回值

当用户单击按钮的时候,Swal.fire返回的promise将返回一个SweetAlertResult对象

键值如下

**isConfirmed**:当确认按钮被点击,返回的result的这个属性将为true

**isDenied**:当拒绝按钮被点击,返回的result的这个属性将为true,当弹窗有输入结果的时候,可以使用**returnInputValueOnDeny: true**返回输入的值

**isDismissed**:当取消按钮被点击,返回的result的这个属性将为true,而dismiss属性将为**Swal.DismissReason.cancel**

**value**:该值来源于窗口弹出,返回的result的这个属性有多种可能的值,当点击确认按钮时为true,拒绝为false,和存在输入框的时候为输入框的值

**dismiss**:当点击取消按钮的时候存在该属性,为取消原因,关于取消原因可以查看接下来的内容

# 取消原因

当用户点击取消按钮的时候,Swal.fire将返回一个对象,包含了{ isDismissed: true,dismiss: reason },其中reason包含了取消的详细原因

原因如下

**Swal.DismissReason.backdrop**:点击了外部背景,相关配置为allowOutsideClick

**Swal.DismissReason.cancel**:点击了取消按钮,相关配置为showCancelButton

**Swal.DismissReason.close**:点击了关闭按钮,相关配置为showCloseButton

**Swal.DismissReason.esc**:按了esc键,相关配置为allowEscapeKey

**Swal.DismissReason.timer**:时间超时,对话框自动关闭,相关配置为timer

如果使用了Swal.close关闭窗口,则Promise返回的obj中isDismissed:为true,但dismiss属性为undefined

# 图标

如下

![图片.png](data/attachment/forum/202111/21/223328kuvauvpvg4a49msj.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "图片.png")

# 输入类型

这里我们也可以限制对话框内的输入类型

首先是text类型

```javascript
const ipAPI = '//api.ipify.org?format=json'

const inputValue = fetch(ipAPI)
.then(response => response.json())
.then(data => data.ip)

const { value: ipAddress } = await Swal.fire({
title: 'Enter your IP address',
input: 'text',
inputLabel: 'Your IP address',
inputValue: inputValue,
showCancelButton: true,
inputValidator: (value) => {
    if (!value) {
      return 'You need to write something!'
    }
}
})

if (ipAddress) {
Swal.fire(`Your IP address is ${ipAddress}`)
}
```

![图片.png](data/attachment/forum/202111/21/223520kbu9vu3jtr9ivu9i.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "图片.png")

`inputLabel`是显示的文本

`inputValue`是显示的值,如果是text,email,number,tel,textarea等类型,则可以传入一个promise值

`inputValidator`对其进行合法性校验

****const** { **value**: ipAddress } = **await** **Swal**.**fire****

这里做了一个结构,对Swal.fire返回的promise做了一个await语法糖,同步等待返回对象,同时对对象进行解构拿到value的值,叫变量ipAddress

并在最后显示出来。

然后是email类型,代码如下

```javascript
const { value: email } = await Swal.fire({
title: 'Input email address',
input: 'email',
inputLabel: 'Your email address',
inputPlaceholder: 'Enter your email address'
})

if (email) {
Swal.fire(`Entered email: ${email}`)
}
```

![图片.png](data/attachment/forum/202111/21/224034zgi5vycq0b0gcimi.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "图片.png")

非常简单,不解释

url类型

```javascript
const { value: url } = await Swal.fire({
input: 'url',
inputLabel: 'URL address',
inputPlaceholder: 'Enter the URL'
})

if (url) {
Swal.fire(`Entered URL: ${url}`)
}
```

![图片.png](data/attachment/forum/202111/21/224100laavjza5zjjup5un.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "图片.png")

password类型

```javascript
const { value: password } = await Swal.fire({
title: 'Enter your password',
input: 'password',
inputLabel: 'Password',
inputPlaceholder: 'Enter your password',
inputAttributes: {
    maxlength: 10,
    autocapitalize: 'off',
    autocorrect: 'off'
}
})

if (password) {
Swal.fire(`Entered password: ${password}`)
}
```

![图片.png](data/attachment/forum/202111/21/224121juacla0iy0e0geay.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "图片.png")

`maxlength`最大长度

`autocapitalize`取消首字母大写

`autocorrect`关闭自动修正,这个可以百度一下看看

textarea类型

```javascript
const { value: text } = await Swal.fire({
input: 'textarea',
inputLabel: 'Message',
inputPlaceholder: 'Type your message here...',
inputAttributes: {
    'aria-label': 'Type your message here'
},
showCancelButton: true
})

if (text) {
Swal.fire(text)
}
```

`inputAttributes`添加到html对象的输入属性,其中键为属性名称,而值为添加的对应值

select类型

```javascript
const { value: fruit } = await Swal.fire({
title: 'Select field validation',
input: 'select',
inputOptions: {
    'Fruits': {
      apples: 'Apples',
      bananas: 'Bananas',
      grapes: 'Grapes',
      oranges: 'Oranges'
    },
    'Vegetables': {
      potato: 'Potato',
      broccoli: 'Broccoli',
      carrot: 'Carrot'
    },
    'icecream': 'Ice cream'
},
inputPlaceholder: 'Select a fruit',
showCancelButton: true,
inputValidator: (value) => {
    return new Promise((resolve) => {
      if (value === 'oranges') {
      resolve()
      } else {
      resolve('You need to select oranges :)')
      }
    })
}
})

if (fruit) {
Swal.fire(`You selected: ${fruit}`)
}
```

`inputOptions`为选项值

![图片.png](data/attachment/forum/202111/21/224808optxa2t3y110p1bt.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "图片.png")

radio类型

```javascript
/* inputOptions can be an object or Promise */
const inputOptions = new Promise((resolve) => {
setTimeout(() => {
    resolve({
      '#ff0000': 'Red',
      '#00ff00': 'Green',
      '#0000ff': 'Blue'
    })
}, 1000)
})

const { value: color } = await Swal.fire({
title: 'Select color',
input: 'radio',
inputOptions: inputOptions,
inputValidator: (value) => {
    if (!value) {
      return 'You need to choose something!'
    }
}
})

if (color) {
Swal.fire({ html: `You selected: ${color}` })
}
```

这里他为了演示,返回了一个promise并设置一秒后结束promise

返回的值是对象,其中键是对应的值,而属性则是名字

![图片.png](data/attachment/forum/202111/21/224938c63uti6932o56ixu.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "图片.png")

checkbox类型

```javascript
const { value: accept } = await Swal.fire({
title: 'Terms and conditions',
input: 'checkbox',
inputValue: 1,
inputPlaceholder:
    'I agree with the terms and conditions',
confirmButtonText:
    'Continue <i class="fa fa-arrow-right"></i>',
inputValidator: (result) => {
    return !result && 'You need to agree with T&C'
}
})

if (accept) {
Swal.fire('You agreed with T&C :)')
}
```

设定了默认值以及单选框文本

file类型

```javascript
const { value: file } = await Swal.fire({
title: 'Select image',
input: 'file',
inputAttributes: {
    'accept': 'image/*',
    'aria-label': 'Upload your profile picture'
}
})

if (file) {
const reader = new FileReader()
reader.onload = (e) => {
    Swal.fire({
      title: 'Your uploaded picture',
      imageUrl: e.target.result,
      imageAlt: 'The uploaded picture'
    })
}
reader.readAsDataURL(file)
}
```

这里没什么特别需要讲解的

range类型

```javascript
Swal.fire({
title: 'How old are you?',
icon: 'question',
input: 'range',
inputLabel: 'Your age',
inputAttributes: {
    min: 8,
    max: 120,
    step: 1
},
inputValue: 25
})
```

进度条类型,min为最小,max为最大,step为阶段提升值,inputValue为默认值

## 提示

不支持多个输入框输入

但是可以通过html以及preConfirm属性来实现。

在preConfirm你可以返回自定义结果,preConfirm可以接受一个promise

例子如下

```javascript
const { value: formValues } = await Swal.fire({
title: 'Multiple inputs',
html:
    '<input id="swal-input1" class="swal2-input">' +
    '<input id="swal-input2" class="swal2-input">',
focusConfirm: false,
preConfirm: () => {
    return [
      document.getElementById('swal-input1').value,
      document.getElementById('swal-input2').value
    ]
}
})

if (formValues) {
Swal.fire(JSON.stringify(formValues))
}
```

# 主题

sweetalert2有多种主题

![图片.png](data/attachment/forum/202111/21/225719wl8a6e6p3at8ntjp.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "图片.png")

![图片.png](data/attachment/forum/202111/21/225729lf5jv55ifucd5cm3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "图片.png")

# 如何引入主题

可以直接引入对应的css文件以及sweetalert2的js文件



```javascript
https://cdn.jsdelivr.net/npm/@sweetalert2/theme-dark@3/dark.css
https://cdn.jsdelivr.net/npm/sweetalert2@9/dist/sweetalert2.min.js
引入以上两个文件
```

关于css文件地址

你可以在

https://cdn.jsdelivr.net/npm/@sweetalert2/themes@latest/

找到对应的文件目录以及对应的css文件。

# 结语

拖了这么久终于给sweetalert2完结了...累死了

执念e1 发表于 2021-11-22 17:21:49

ggnb!!!

李恒道 发表于 2021-11-22 20:13:47

执念e1 发表于 2021-11-22 17:21
ggnb!!!

呜呜呜
现在没人看,越到后期看的人越少了

shan869 发表于 2021-12-10 21:23:05

李恒道 发表于 2021-11-22 20:13
呜呜呜
现在没人看,越到后期看的人越少了

谢谢,不要气馁,好东西是会发光的。我在努力学习中。{:4_106:}

李恒道 发表于 2021-12-11 13:49:42

shan869 发表于 2021-12-10 21:23
谢谢,不要气馁,好东西是会发光的。我在努力学习中。

谢谢哥哥,哥哥加油学

shan869 发表于 2021-12-11 15:43:18

李恒道 发表于 2021-12-11 13:49
谢谢哥哥,哥哥加油学
请教哥哥,VUE网页是不是不能用.val()赋值(这是QQ名为PIN 的一位哥哥说的,是论坛哪位哥哥?他好像也是很厉害的人物)?也有说是因为iframe框架不能获取元素(可控制台是能通过document.querySelectorAll("input").value='3324325'),
类似这样直接赋值的。究竟vue应该用什么方法实现油猴直接输入文字?我自己看了很多文章都搞不定。可以搞一篇教程看看吗?谢谢

李恒道 发表于 2021-12-11 17:30:11

shan869 发表于 2021-12-11 15:43
请教哥哥,VUE网页是不是不能用.val()赋值(这是QQ名为PIN 的一位哥哥说的,是论坛哪位哥哥?他好像也是很 ...

vue是可以赋值的
设置值之后根据https://bbs.tampermonkey.net.cn/thread-1250-1-1.html
投递过去,即可设置值
或者直接拿vm实例https://bbs.tampermonkey.net.cn/thread-1425-1-1.html

shan869 发表于 2021-12-11 17:43:14

李恒道 发表于 2021-12-11 17:30
vue是可以赋值的
设置值之后根据https://bbs.tampermonkey.net.cn/thread-1250-1-1.html
投递过去,即可 ...

谢谢,教程没看完,我看完不懂再请教。

李恒道 发表于 2021-12-11 20:37:13

shan869 发表于 2021-12-11 17:43
谢谢,教程没看完,我看完不懂再请教。

哥哥加油

cuicui 发表于 2022-1-14 01:28:27

还会接着更新吗?等更新
页: [1] 2
查看完整版本: [油猴脚本开发指南]SweetAlert2进阶