目录导航

## 窗口类型

### 文本窗口

#### 打开一个字符串文本

    layx.html('str','字符串文本','Hello Layx!');

#### 打开一个HTMLElement 窗口

    layx.html('dom','HTMLElement 窗口',document.getElementById('dom'));

Layx 网页弹窗最佳选择.

#### HTML字符串窗口

    layx.html('htmlstr','HTML字符串窗口',layx.multiLine(function () {/*

                 <style type="text/css">
                 #about-layx{
                        padding:10px;
                        line-height:1.5;
                }

                #about-layx h2{
                    border-bottom:1px solid #ccc;
                }

                #about-layx label {
                    margin: 0 2px;
                    padding: 0 5px;
                    white-space: nowrap;
                    border: 0;
                    background-color: #f8f8f8;
                    border-radius: 3px;
                    display:inline-block;
                }
                 </style>

                 <div id="about-layx">
                    <h2>序言</h2>
                    <p>Layx 诞生于一次C/S架构系统往B/S架构系统迁移项目中。起初，我们想在B/S架构上实现类C/S架构窗口功能，但百度、谷歌过后依然没能找到合适的Javascript插件。于是乎在2018年05月01日五一劳动节期间连夜赶工创造出了 Layx 。</p>
                    <p>目前 Layx 拥有和C/S架构一样灵活的操作方式，支持网页多窗口、多任务协同操作，支持窗口各种事件。</p>
                    <h2>信息</h2>
                    <ul>
                        <li><label>原创作者</label>：百小僧</li>
                        <li><label>开源协议</label>：MIT</li>
                        <li><label>当前版本</label>：v2.1.0</li>
                        <li><label>发布日期</label>：2018.05.19</li>
                        <li><label>交流Q群</label>：18863883</li>
                    </ul>
                    <h2>特性</h2>
                    <ul>
                        <li>纯原生Javascript实现，不依赖任何第三方框架</li>
                        <li>支持IE10+（含IE10）、Chrome、Firefox、Opera、Edge等主流浏览器</li>
                        <li>支持多种窗口类型：文本窗口，页面窗口，窗口组，提示窗口，消息窗口，询问窗口，输入窗口，加载窗口</li>
                        <li>支持窗口最大化、最小化、恢复、置顶、关闭控制及事件监听</li>
                        <li>支持窗口阻隔、窗口闪烁功能</li>
                        <li>支持窗口点击标题获取焦点、点击内容/页面获取焦点</li>
                        <li>支持窗口图标定制、操作按钮定制</li>
                        <li>支持窗口四个方向拖动及方向控制</li>
                        <li>支持窗口八个方向拖曳大小及拖曳方向控制</li>
                        <li>支持窗口自动获取页面标题</li>
                        <li>支持窗口位置记录及恢复</li>
                        <li>支持窗口相互通讯</li>
                        <li>支持窗口设定自动关闭</li>
                        <li>支持窗口外观控制、状态栏、透明度控制</li>
                        <li>支持窗口操作拦截器、可以拦截任何不正常操作</li>
                        <li>支持窗口初始化位置、宽高度、最小化宽高度控制</li>
                        <li>支持窗口加载文字控制</li>
                        <li>支持窗口滚动条自能判断</li>
                        <li>支持窗口最小化统一管理</li>
                        <li>支持滚动条智能判断</li>
                    </ul>
                    <h2>项目</h2>
                    <ul>
                        <li>Gitee：<a href="https://gitee.com/monksoul/LayX" target="_blank">https://gitee.com/monksoul/LayX</a></li>
                        <li>Github：<a href="https://github.com/MonkSoul/Layx"  target="_blank">https://github.com/MonkSoul/Layx</a></li>
                    </ul>
                    <h2>捐赠</h2>
                    <p>如果 Layx 对您有帮助，可以请 作者 喝杯咖啡</p>
                    <img src="./code.jpg" style="width:100%;display:block;" />
                 </div>

                */}));

### 网页窗口

#### 打开一个本地网页

    layx.iframe('localsite','本地网页','./iframe.html');

#### 打开淘宝网

    layx.iframe('localsite','淘宝网','https://www.taobao.com');

### 消息窗口

#### 打开一个消息窗口

    layx.msg('Layx 网页弹窗最佳选择.');

### 提示窗口

#### 打开一个提示窗口

    layx.alert('版本更新','Layx v2.1.0 版本更新啦！');

### 询问窗口

#### 打开一个询问窗口

    layx.confirm('作何选择','你会在下一个系统使用 Layx 吗？',function(id){
        alert('感谢您的支持！');
        layx.destroy(id);
    });

### 输入窗口

#### 打开一个输入窗口

    layx.prompt('Layx 体验报告','写下您对 Layx 的建议：',function(id,value,textarea){
        alert(value);
        layx.destroy(id);
    });

### 加载窗口

#### 打开一个加载窗口

    layx.load('loadId','数据正在加载中，请稍后');

    // 5 秒后自动关闭
    setTimeout(function(){
        layx.destroy('loadId');
    },5000);

### 操作窗口

#### 打开一个操作窗口

    layx.iframe('operator','带操作按钮窗口','./iframe.html',{
        statusBar:true,
        buttons:[
            {
                label:'保存',
                callback:function(id){
                    // 获取 iframe 页面 window对象
                    var contentWindow=layx.getFrameContext(id);
                    alert(contentWindow.document.body.innerHTML);

                    layx.destroy(id);
                }
            },
            {
                label:'取消',
                callback:function(id){
                    layx.destroy(id);
                }
            }
        ]
    });

### 窗口组

#### 打开一个窗口组窗口

    layx.group('group',[
        {
            id:'group1',
            title:'文本窗口',
            content:'Layx 网页弹窗最佳选择.'
        },
        {
            id:'group2',
            title:'网页窗口',
            type:'url',
            url:'./iframe.html'
        },
        {
            id:'taobao',
            title:'淘宝网',
            type:'url',
            url:'https://www.taobao.com'
        }
    ],1);

### 倒计时窗口

#### 打开一个倒计时关闭窗口

    layx.iframe('settimeout','打开一个倒计时关闭窗口','./iframe.html',{
        autodestroy:5000
    });

### 遮罩、阻隔窗口

#### 打开一个遮罩、阻隔窗口

    layx.iframe('shadow','打开一个遮罩、阻隔窗口，点击窗口外试试','./iframe.html',{
        shadable:true
    });

### 置顶窗口

#### 打开一个置顶窗口

    layx.iframe('sticktop','打开一个置顶窗口，再打开另外的窗口试试','./iframe.html',{
        alwaysOnTop:true,
        stickMenu:true,  // 可选，是否显示切换置顶按钮
        position:[100,100]
    });

## 窗口外观

### 主窗口外观

#### 默认外观

    layx.iframe('default-style','默认外观','./iframe.html');

#### 灰色背景

    layx.iframe('gray-style','灰色背景','./iframe.html',{
        bgColor:'#ccc'
    });

#### 透明窗口

    layx.iframe('opacity-style','透明窗口','./iframe.html',{
        opacity:0.5
    });

#### 无边框

    layx.iframe('noborder-style','无边框','./iframe.html',{
        border:false
    });

#### 无阴影

    layx.iframe('noshadow-style','无阴影','./iframe.html',{
        shadow:false
    });

#### 红色边框

    layx.iframe('redborder-style','红色边框','./iframe.html',{
        border:'1px solid #f00'
    });

#### 无标题栏

    layx.html('nocontrol-style','无标题栏','<button style="margin:10px;" onclick="layx.destroy(\'nocontrol-style\');">关闭</button>',{
        control:false
    });

#### 带状态栏

    layx.iframe('statusbar-style','带状态栏','./iframe.html',{
        statusBar:'<div style="line-height:25px;padding:0 10px;" >我是状态栏内容</div>'
    });

#### 自定义外观，比如圆角

    layx.iframe('radiu-style','自定义外观，比如圆角','./iframe.html',{
        style:layx.multiLine(function(){/*

            #layx-radiu-style{
                border-radius:4px;
                -webkit-border-radius:4px;
                -moz-border-radius:4px;
                -ms-border-radius:4px;
            }

            #layx-radiu-style .layx-window-icon{
                color:#f00;
            }

    */})
    });

在这里，可以尽情写 css 样式了，改成任何您想要的外观

### 标题栏外观

#### 紫色标题栏

    layx.iframe('purple-control-style','紫色标题栏','./iframe.html',{
        controlStyle:'background-color: #7719aa; color:#fff;',
        style:layx.multiLine(function(){/*

        #layx-purple-control-style .layx-inlay-menus .layx-icon:hover {
            background-color: #9953c0;
        }

    */})
    });

#### 没有窗口图标

    layx.iframe('no-icon','没有窗口图标','./iframe.html',{
        icon:false
    });

#### 自定义图标

    layx.iframe('custom-icon','自定义图标','./iframe.html',{
        icon:'<img src="logo.png" style="height:22px;display:block;" />'
    });

#### 不显示标题、图标

    layx.iframe('no-title',null,'./iframe.html',{
        icon:false
    });

#### 显示置顶按钮

    layx.iframe('stick-show','显示置顶按钮','./iframe.html',{
        stickMenu:true
    });

#### 不显示最小化按钮

    layx.iframe('minhide','不显示最小化按钮','./iframe.html',{
        minMenu:false
    });

#### 不显示最大化按钮

    layx.iframe('maxhide','不显示最大化按钮','./iframe.html',{
        maxMenu:false
    });

#### 不显示关闭按钮

    layx.html('closehide','不显示关闭按钮','<button style="margin:10px;" onclick="layx.destroy(\'closehide\');">关闭</button>',{
        closeMenu:false
    });

#### 只显示关闭按钮

    layx.iframe('onlyclose','只显示关闭按钮','./iframe.html',{
        minMenu:false,
        maxMenu:false
    });

#### 自定义标题栏左边区域

    layx.iframe('leftbar','自定义标题栏左边区域','./iframe.html',{
        icon:'<button>按钮一</button> <img src="logo.png" style="height:22px;vertical-align: middle;" /> <button>按钮二</button>'
    });

#### 自动获取iframe标题

    layx.iframe('autotitle',null,'./iframe.html',{
       useFrameTitle:true
    });

## 行为控制

### 拖动控制

#### 默认拖动

    layx.iframe('defaultmove','鼠标拖动标题栏看看','./iframe.html');

#### 只允许垂直拖动

    layx.iframe('onlyvertical','只允许垂直拖动','./iframe.html',{
        moveLimit:{
            horizontal:true
        }
    });

#### 只允许水平拖动

    layx.iframe('onlyhorizontal','只允许水平拖动','./iframe.html',{
        moveLimit:{
            vertical:true
        }
    });

#### 不允许拖出可视窗口

    layx.iframe('noallowout','不允许拖出可视窗口','./iframe.html',{
        moveLimit:{
            leftOut: false,
            rightOut: false,
            topOut: false,
            bottomOut: false,
        }
    });

#### 不允许拖动

    layx.iframe('nomove','不允许拖动','./iframe.html',{
        movable:false
    });

#### 四个方向限制，比如不允许拖出底部

    layx.iframe('nomovebottom','四个方向限制，比如不允许拖出底部','./iframe.html',{
        moveLimit:{
            leftOut: true,
            rightOut: true,
            topOut: true,
            bottomOut: false,
        }
    });

### 拖曳大小控制

#### 默认可以8个方向拖曳改变大小

    layx.iframe('defaultresize','默认可以8个方向拖曳改变大小','./iframe.html');

#### 8个方向拖曳大小控制，比如不允许顶部和底部拖曳改变

    layx.iframe('notopbottomresize','8个方向拖曳大小控制，比如不允许顶部和底部拖曳改变','./iframe.html',{
        resizeLimit: {
            t: true,
            r: false,
            b: true,
            l: false,
            lt: false,
            rt: false,
            lb: false,
            rb: false
        }
    });

#### 不允许改变大小

    layx.iframe('noresize','不允许改变大小','./iframe.html',{
        resizable:false
    });

## 窗口大小、位置

### 窗口大小

#### 默认大小

    layx.iframe('defaultsize','默认大小（宽800px，高600px）','./iframe.html');

#### 自定义宽度、高度

    layx.iframe('customsize','自定义宽度、高度（宽300px，高300px）','./iframe.html',{
        width:300,
        height:300
    });

#### 最小高度、宽度

    layx.iframe('minwidthheight','拖曳调整浏览器窗口大小试试，最小300px x 300px','./iframe.html',{
        minWidth:300,
        minHeight:300
    });

### 窗口位置

#### 中间打开

    layx.iframe('resize-ct','中间打开','./iframe.html');

#### 左上角打开

    layx.iframe('resize-lt','左上角打开','./iframe.html',{
        position:'lt'
    });

#### 右上角打开

    layx.iframe('resize-rt','右上角打开','./iframe.html',{
        position:'rt'
    });

#### 左下角打开

    layx.iframe('resize-lb','左下角打开','./iframe.html',{
        position:'lb'
    });

#### 右下角打开

    layx.iframe('resize-rb','右下角打开','./iframe.html',{
        position:'rb'
    });

#### 上边中间打开

    layx.iframe('resize-tc','上边中间打开','./iframe.html',{
        position:'tc'
    });

#### 左边中间打开

    layx.iframe('resize-lc','左边中间打开','./iframe.html',{
        position:'lc'
    });

#### 右边中间打开

    layx.iframe('resize-rc','右边中间打开','./iframe.html',{
        position:'rc'
    });

#### 下边中间打开

    layx.iframe('resize-bc','下边中间打开','./iframe.html',{
        position:'bc'
    });

#### 自定义位置

    layx.iframe('resize-custom','自定义位置（上边100px，左边200px）','./iframe.html',{
        position:[100,200]
    });

#### 自定义位置（组合模式）

    layx.iframe('resize-custom','自定义位置（组合模式，顶部中间并距离20px）','./iframe.html',{
        position:[20,'tc']
    });

## 窗口事件

### 加载事件

#### 加载前后控制

    layx.iframe('event-onload','加载前后控制','./iframe.html',{
        event:{
            onload:{
                before:function(layxWindow,winform){
                    alert("加载之前");
                    console.log(new Date()+"加载之前~")
                    console.log(winform);
                    console.log("=============分割线===============");
                },
                after: function (layxWindow, winform) {
                    alert("加载之后");
                    console.log(new Date()+"加载之后~")
                    console.log(winform);
                    console.log("=============分割线===============");
                }
            }
        }
    });

请打开控制台查看

### 最小化事件

    layx.iframe('event-onmin','最小化前后控制','./iframe.html',{
        event:{
            onmin:{
                before:function(layxWindow,winform){
                    alert("最小化之前");
                    console.log(new Date()+"最小化之前~")
                    console.log(winform);
                    console.log("=============分割线===============");
                },
                after: function (layxWindow, winform) {
                    alert("最小化之后");
                    console.log(new Date()+"最小化之后~")
                    console.log(winform);
                    console.log("=============分割线===============");
                }
            }
        }
    });

请打开控制台查看

### 最大化事件

    layx.iframe('event-onmax','最大化前后控制','./iframe.html',{
        event:{
            onmax:{
                before:function(layxWindow,winform){
                    alert("最大化之前");
                    console.log(new Date()+"最大化之前~")
                    console.log(winform);
                    console.log("=============分割线===============");
                },
                after: function (layxWindow, winform) {
                    alert("最大化之后");
                    console.log(new Date()+"最大化之后~")
                    console.log(winform);
                    console.log("=============分割线===============");
                }
            }
        }
    });

请打开控制台查看

### 恢复事件

    layx.iframe('event-onrestore','恢复前后控制','./iframe.html',{
        event:{
            onrestore:{
                before:function(layxWindow,winform){
                    alert("恢复之前");
                    console.log(new Date()+"恢复之前~")
                    console.log(winform);
                    console.log("=============分割线===============");
                },
                after: function (layxWindow, winform) {
                    alert("恢复之后");
                    console.log(new Date()+"恢复之后~")
                    console.log(winform);
                    console.log("=============分割线===============");
                }
            }
        }
    });

请打开控制台查看

### 关闭事件

    layx.iframe('event-ondestroy','关闭前后控制','./iframe.html',{
        event:{
            ondestroy:{
                before:function(layxWindow,winform){
                    alert("关闭之前");
                    console.log(new Date()+"关闭之前~")
                    console.log(winform);
                    console.log("=============分割线===============");
                },
                after: function (layxWindow, winform) {
                    alert("关闭之后");
                    console.log(new Date()+"关闭之后~")
                    console.log(winform);
                    console.log("=============分割线===============");
                }
            }
        }
    });

请打开控制台查看

#### 拖动事件

    layx.iframe('event-onmove','拖动前中后控制','./iframe.html',{
        event:{
            onmove:{
                before:function(layxWindow,winform){
                    console.log(new Date()+"拖动之前~")
                    console.log(winform);
                    console.log("=============分割线===============");
                },
                progress:function(layxWindow,winform){
                    console.log(new Date()+"拖动之中~")
                    console.log(winform);
                    console.log("=============分割线===============");
                },
                after: function (layxWindow, winform) {
                    console.log(new Date()+"拖动之后~")
                    console.log(winform);
                    console.log("=============分割线===============");
                }
            }
        }
    });

请打开控制台查看

#### 拖曳大小事件

    layx.iframe('event-onresize','拖曳大小前中后控制','./iframe.html',{
        event:{
            onresize:{
                before:function(layxWindow,winform){
                    console.log(new Date()+"拖曳大小之前~")
                    console.log(winform);
                    console.log("=============分割线===============");
                },
                progress:function(layxWindow,winform){
                    console.log(new Date()+"拖动大小之中~")
                    console.log(winform);
                    console.log("=============分割线===============");
                },
                after: function (layxWindow, winform) {
                    console.log(new Date()+"拖曳大小之后~")
                    console.log(winform);
                    console.log("=============分割线===============");
                }
            }
        }
    });

请打开控制台查看

## 更多示例

### 事件组合

#### 自动最大化窗口

    layx.iframe('maxauto','自动最大化窗口','./iframe.html',{
        event:{
            onload:{
                after:function(layxWindow,winform){
                    layx.max(winform.id);
                }
            }
        }
    });

#### 只有输入Layx才能关闭窗口

    layx.prompt('请输入当前框架的名称','请输入Layx名字：',function(id,value,textarea){
        layx.destroy(id);
    },{
        event:{
            ondestroy: {
                 before: function (layxWindow, winform) {
                    var textarea=layx.getPromptTextArea(winform.id);
                    if(textarea.value==="Layx"){
                        alert("你正确输入了 Layx");
                    }
                    else{
                        alert("您输入的是："+textarea.value+"，您必须输入 Layx 才能关闭 ");
                        return false;
                    }
                }
            }
        }
    });

### 其他示例

#### 定制加载提示文本

    layx.iframe('loadtext','定制加载提示文本','https://www.taobao.com',{
        loaddingText: '正在加载淘宝网官方网站，请稍后哦'
    });

#### 定制倒计时文本

    layx.iframe('destroysettimeout','定制倒计时文本','./iframe.html',{
        autodestroy:5000,
        autodestroyText: '<div style="padding: 0 8px; ">亲~，此窗口将在 <strong>{second}</strong> 秒内自动关闭哦.</div>'
    });

#### 定制询问框按钮

    layx.confirm('温馨提示','你还为保存文本内容，请选择操作。',null,{
        buttons:[
            {
                label:'保存文本',
                callback:function(id){
                    alert("你点击了保存文本");
                }
            },
            {
                label:'确定',
                callback:function(id){
                    alert("你点击了确定");
                }
            },
            {
                label:'关闭',
                callback:function(id){
                    alert("你点击了关闭");
                    layx.destroy(id);
                }
            }
        ]
    });

## 常用方法及窗口通讯

### 常用方法

#### 获取Layx版本

    alert(layx.v);

#### 通用打开窗口方法

    layx.open({
        id:'common',
        title:'通用打开窗口方法',
        content:'<div style="padding:10px;">Layx 所有的窗口类型全部都是基于此操作方法创建的。</div>'
    });

#### 获取所有打开窗口列表

    var windows=layx.windows();

    var jsonStr=JSON.stringify(windows, null, 4);
    console.log(jsonStr);
    alert(jsonStr);

请打开控制台查看

#### 获取单个窗口winform对象

    // 第一种方法，直接接收返回值
    var winform = layx.iframe('single','测试操作方法、通讯窗口','./iframe.html');
    alert(JSON.stringify(winform, null, 4));

    // 第二种方法，通过 layx.getWindow(id) 获取窗口的winform对象
    var winform2 = layx.getWindow('single');
    alert(JSON.stringify(winform2, null, 4));

请打开控制台查看

#### 设置窗口标题

第一步：先打开窗口才能测试

第二步：设置窗口标题

    layx.setTitle('iframe-demo','我是新的标题');

#### 设置窗口标题（自动获取页面标题）

第一步：先打开窗口才能测试

第二步：设置窗口标题（自动获取页面标题）

    layx.setTitle('iframe-demo',null,true);

#### 设置文本窗口内容

第一步：先打开窗口才能测试

第二步：设置文本窗口内容

    layx.setContent('text-demo',new Date()+' 我是新设置的内容 ');

#### 设置网页窗口地址

第一步：先打开窗口才能测试

第二步：设置网页窗口地址为 https://www.taobao.com/

    layx.setUrl('iframe-demo','https://www.taobao.com/');

#### 设置网页窗口地址（自动获取标题）

第一步：先打开窗口才能测试

第二步：设置网页窗口地址为 ./child.html

    layx.setUrl('iframe-demo1','./child.html');

测试窗口必须设置 useFrameTitle:true

#### 闪烁一下窗口

    layx.flicker('layx');

#### 最大化窗口

    layx.max('layx');

#### 恢复窗口

    layx.restore('layx');

#### 最小化窗口

第一步：先打开窗口才能测试

第二步：设置最小化

    layx.min('iframe-demo');

#### 置顶/取消置顶

    layx.stickToggle('layx');

注意看 Layx 演示案例 右上角置顶图标颜色变化

#### 设置窗口位置

    layx.setPosition('layx','ct');

#### 关闭窗口

第一步：先打开窗口才能测试

第二步：关闭窗口

    layx.destroy('iframe-demo');

#### 重载页面窗口

第一步：先打开窗口才能测试

第二步：重载页面窗口

    layx.reloadFrame('iframe-demo');

#### 关闭所有窗口

第一步：先打开窗口才能测试

第二步：关闭所有窗口

    layx.destroyAll();

注意看 设置 closable:false 窗口不可关闭

#### 设置窗口组标题

    layx.setGroupTitle('layx','demo','演示示例');

注意看 当前文档的标题哦

#### 设置窗口组文本内容

第一步：先打开窗口组才能测试

第二步：设置窗口组一内容

    layx.setGroupContent('group-demo','group1','我是新设置的内容');

#### 设置窗口组页面窗口URL地址

第一步：先打开窗口组才能测试

第二步：设置窗口组二URL地址

    layx.setGroupUrl('group-demo','group2','https://www.taobao.com');

#### 设置窗口组页面窗口URL地址（自动获取标题）

第一步：先打开窗口组才能测试

第二步：设置窗口组二URL地址

    layx.setGroupUrl('group-demo2','group2','./child.html');

窗口组二必须设置 useFrameTitle:true

#### 设置窗口组索引

    layx.setGroupIndex('layx','info');

#### 重载窗口组页面窗口

第一步：先打开窗口组才能测试

第二步：重载窗口组页面窗口

    layx.reloadGroupFrame('group-demo','group2');

### 窗口通讯（页面窗口）

#### 获取 页面窗口对象，并获取页面HTML

第一步：先打开窗口才能测试

第二步：获取页面HTML

    var win = layx.getFrameContext('iframe-demo');
    alert(win.document.body.innerHTML);

#### 获取 页面窗口对象，并设置页面HTML

第一步：先打开窗口才能测试

第二步：设置页面HTML

    var win = layx.getFrameContext('iframe-demo');
    win.document.body.innerHTML='<label>Hello Layx!</label>';

#### 获取 页面窗口对象，并调用页面定义方法

第一步：先打开窗口才能测试

第二步：调用页面定义方法 iframeFunc

    var win = layx.getFrameContext('iframe-demo');
    win.iframeFunc();

#### 获取窗口组页面窗口HTML

第一步：先打开窗口组才能测试

第二步：获取窗口组二HTML

    var win = layx.getGroupFrameContext('group-demo','group2');
    alert(win.document.body.innerHTML);

#### 设置窗口组页面窗口HTML

第一步：先打开窗口组才能测试

第二步：设置窗口组二HTML

    var win = layx.getGroupFrameContext('group-demo','group2');
    win.document.querySelector("label").innerHTML="Hello Layx!";

#### 调用窗口组页面窗口定义的方法

第一步：先打开窗口组才能测试

第二步：调用页面定义方法 iframeFunc

    var win = layx.getGroupFrameContext('group-demo','group2');
    win.iframeFunc();

如果 Layx 对您有帮助，可以请 作者 喝杯咖啡