首页

JS设计模式之单例模式、组合模式、观察者模式、策略模式

前端达人

好,下面我将结合一些实例,说一下我对组合模式以及观察者模式的了解:



1、组合模式:



组合模式在对象间形成树形结构;

组合模式中基本对象和组合对象被一致对待;

无须关心对象有多少层, 调用时只需在根部进行调用;

将多个对象的功能,组装起来,实现批量执行;

想象我们现在手上有个万能遥控器, 当我们回家, 按一下开关, 下列事情将被执行:



到家了,开门

开电脑

开音乐




// 先准备一些需要批量执行的功能
class GoHome{
    init(){
        console.log("到家了,开门");
    }
}
class OpenComputer{
    init(){
        console.log("开电脑");
    }
}
class OpenMusic{
    init(){
        console.log("开音乐");
    }
}

// 组合器,用来组合功能
class Comb{
    constructor(){
        // 准备容器,用来防止将来组合起来的功能
        this.skills = [];
    }
    // 用来组合的功能,接收要组合的对象
    add(task){
        // 向容器中填入,将来准备批量使用的对象
        this.skills.push(task);
    }
    // 用来批量执行的功能
    action(){
        // 拿到容器中所有的对象,才能批量执行
        this.skills.forEach( val => {
            val.init();
        } );
    }
}

// 创建一个组合器
var c = new Comb();

// 提前将,将来要批量操作的对象,组合起来
c.add( new GoHome() );
c.add( new OpenComputer() );
c.add( new OpenMusic() );

// 等待何时的时机,执行组合器的启动功能
c.action();
    // 在内部,会自动执行所有已经组合起来的对象的功能



由此,我们可以总结一下组合模式的特点


1.批量执行
2.启动一个方法,会遍历多个方法,同时执行,有点类似于递归的感觉
3.组合模式略微耗性能,但是执行方便
 目前只是一个基础组合。
 高级组合:
1.组合成树状结构,每个对象下,还会有自己的子对象
2.如果执行了父对象的某个方法,所有的子对象会跟随执行
3.组合模式一般建议使用在动态的html结构上,因为组合模式的结构和html的结构,出奇的一致
4.基本对象和组合对象被一致对待, 所以要保证基本对象(叶对象)和组合对象具有一致方法


2、观察者模式:

观察者模式也叫也叫Observer模式、订阅/发布模式,也是由GoF提出的23种软件设计模式的一种。
观察者模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态,或者说执行对应对象的方法(主题数据改变,通知其他相关个体,做出相应的数据更新)。
这种设计模式可以大大降低程序模块之间的耦合度,便于更加灵活的扩展和维护。
以观察的角度,发现对应的状况,处理问题。
观察者模式包含两种角色:
①观察者(订阅者):会随时更新自身的信息或状态(订阅者可以随时加入或离开);
②被观察者(发布者):接收到发布者发布的信息,从而做出对应的改变或执行。
很方便的实现简单的广播通信,实现一对多的对应关系。
核心思想:观察者只要订阅了被观察者的事件,那么当被观察者的状态改变时,被观察者会主动去通知观察者,而无需关心观察者得到事件后要去做什么,实际程序中可能是执行订阅者的回调函数。
Javascript中实现一个例子:


HTML 学习总结2 框架 表单

前端达人

这是HTML学习总结系列的第二篇,第一篇在这里:

HTML 学习总结1入门 基本概念、格式 文字标签 图片标签 链接标签 表格标签 注释

这次的学习内容相较第一次分类少,但是比较杂。



框架集标签

框架标签是将网页设置成网页框架的一种双标签,被设计成框架的网页被切分成若干区域,没有实际的内容,只当做框架用于镶嵌其它的网页。

那么,这个标签是:

<frameset></frameset>

框架集标签的属性

使用的时候需要将HTML文件中的body标签部分替换为框架标签,写成这样:



<html>
    <head></head>
    <frameset rows="500,*" border="3" noresize="noresize">
    </frame>
</html>

看上面的代码,用frameset替换掉body不难理解,毕竟我们约定做框架的网页不具有实体内容
接着,这里提到了框架标签的三个属性,分别为:

rows/cols 框架的分行或分列
border 分隔框的宽度
noresize 大小是否可调
现在来分别解释一下

第一个,rows 或cols 属性,代表了框架的分行或分列的情况,在引号内书写该属性的值的时候,不需要指明分成几栏,只需要指明每一栏占据的宽度或高度(单位为像素)并使用逗号隔开。浏览器在解析的时候会计算到底分成了几栏。另外,不指定宽度而使其占据剩余位置时,可以使用通配符 “ * ”。

第二个,border 属性,代表了分隔框的宽度,这是属性的数值单位是像素。所以如果你不想加入边框,则可以将它设置为零。

第三个,noresize 属性,表示我们的框架的大小是否可调,frameset标签默认为大小可调,当用户鼠标移动到边框上时,他可以拖拽改变大小。所以如果不想让用户随意改变框架大小,那么可以选择使用这个属性 (当然,也可以选择把边框的宽度设为零,让他找不到)。 这个属性的值同属性名称一样。

最后还需要说明的是:框架集标签是可以进行嵌套的,也就是说,在已经分出来的框架中,我们可以借着分栏。

在框架内镶嵌网页
刚刚我们使用 frameset 标签将网页变成框架并划分成了若干区域,每一个区域都是一个单独的可显示页面的子网页(笔者起的名)。现在,我们需要在这些区域内为它镶嵌上一个网页,这需要用到frame这个单标签在框架下添加网页,它的写法如下:

<frame src="...." name="...." />
1
这里可以看到 frame 标签的两个属性; src 和 name 。它们分别代表着添置连接(这是一个超链接,网页,HTML文件,图片等都是可以的。有关超链接的信息,可参照上一篇学习总结或者问问度娘 ),以及框架名称。

框架的命名,很主要的一个原因在于可以重复利用一个框架,即在其他标签使用时,可以在某个框架上显示相应内容。还记得上一篇中,我们提到的链接标签 target 属性中的 “某框架名称” 这个值吗?在为框架命名后,就可以使用上述的 target 用法,将打开的网页放在某个框架中了。

综上,举个例子:

先来创造一个带有嵌套的框架
<!--frame-->
<html>
    <head></head>
    <frameset rows="200,*" border="5" noresize="noresize">
        <frame src="title.html" name="title" />
        <frameset cols="200,*">
            <frame src="selection_bar.html" />
            <frame name="output_page" />
        </frameset>
    </frameset>
</html>



<!--title-->
<html>
    <head></head>
    <body>
        <font size="7" color="blue">
            The test page
        </font>
    </body>
</html>



<!--selection_bar-->
<html>
    <head></head>
    <body>
        <font size="5" color="red">
            Please select websites.
        </font>
        <br /><br />
        <a href="http://www.baidu.com" target="output_page"/>百度一下<br /><br />
        <a href="https://www.csdn.net" target="output_page"/>CSDN <br /><br />
    </body>
</html>

最后来看下结果:

点击查看原图


点击查看原图点击查看原图




vue父组件向子组件传值

前端达人

非常简单,相信大家一看就懂

复制到浏览器即可使用,注意别忘了引入vue哦


<div id="app">
    <div>{{pmsg}}</div>
    <menu-item :title='ptitle' :content='ptitle'></menu-item>
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
    //父组件向子组件传值-基本使用
    Vue.component('menu-item', {
        props: ['title', 'content'],
        data: function() {
            return {
                msg: '子组件本身的数据'
            }
        },
        template: `<div>
      <p>{{msg}}</p>
      <p>{{title}}</p>
      <p>{{content}}</p>
      </div>`
    });
    var vm = new Vue({
        el: '#app',
        data: {
            pmsg: '父组件中内容',
            ptitle: '动态绑定属性'
        }
    });
</script>
————————————————
版权声明:本文为CSDN博主「温柔的坚持」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43745003/article/details/104908639

JS的原型介绍及原型的继承

前端达人

前言

在学习JS中的原型,原型链,继承这些知识之前,我们先学习下基础知识:函数和对象的关系。

我们一直都知道,函数也是对象的一种,因为通过instanceof就可以判断出来。但是函数和对象的关系并不是简单的包含和被包含的关系,这两者之间的关系还是有点复杂的。接下来我们就来捋一捋。



首先,阐述一点,对象都是通过函数创建的

对于下面这种类型的代码,一般叫做“语法糖”

var obj = {a:10,b:20};
var arr = [5, 'x', true];



但是,其实上面这段代码的实质是下面这样的:


//var obj = { a: 10, b: 20 };
//var arr = [5, 'x', true];

 var obj = new Object();
 obj.a = 10;
 obj.b = 20;

 var arr = new Array();
 arr[0] = 5;
 arr[1] = 'x';
 arr[2] = true;



而Object和Array都是函数,可以自己用typeof函数进行验证。
所以,可以得出:对象都是通过函数创建的

正文
说完了前言,接下来我们进入正题。

原型prototype
在前言中,我们说了函数也是一种对象,所以函数也是属性的集合,同时,也可以对函数进行自定义属性。
每个函数都有一个属性——prototype。这个prototype的属性值是一个对象(属性的集合),默认只有一个叫做constructor的属性,指向这个函数本身.

“隐式原型”proto
我们先看一段非常常见的代码:
function Fn() { }
   Fn.prototype.name = '张三';
    Fn.prototype.getAge = function () {
       return 12;
};
   var fn = new Fn();
   console.log(fn.name);
   console.log(fn.getAge ());

即,Fn是一个函数,fn对象是从Fn函数new出来的,这样fn对象就可以调用Fn.prototype中的属性。

但是,因为每个对象都有一个隐藏的属性——“proto”,这个属性引用了创建这个对象的函数的prototype。即:fn.proto === Fn.prototype
那么,这里的_proto_到底是什么呢?

其实,这个__proto__是一个隐藏的属性,javascript不希望开发者用到这个属性值,有的低版本浏览器甚至不支持这个属性值。

var obj = {};
console.log(obj.__proto__);

每个对象都有一个_proto_属性,指向创建该对象的函数的prototype。

构造函数、原型、实例之间的关系
实例,原型对象,构造函数,三者之间的关系:

(1) 实例有__proto__属性指向原型对象

(2) 原型对象有constructor指针指向构造函数

(3)构造函数又有prototype属性指向原型对象
点击查看原图


实例和原型关系检测

isPrototypeOf()函数,用于检测两个对象之间似乎否存在原型关系,使用方法如下:

  // 查看 Fn 的 prototype 对象,是否是 f 原型
  Fn.prototype.isPrototypeOf(f);   



 //// 查看 f 对象是否是构造函数 Fn 的实例
 //console.log(f instanceof Fn); 
 //// 查看 f 对象是否是构造函数 Fn 的实例    
 //console.log(f instanceof Object); 

    function Fn(){}
    function Fun(){}
    var f = new Fn();
    console.log( f.__proto__ === Fn.prototype );            // t

    console.log( Fn.prototype.isPrototypeOf(f) );           // t
    console.log( Fun.prototype.isPrototypeOf(f) );          // f
    console.log( Object.prototype.isPrototypeOf(f) );       // t

    console.log( f instanceof Fn );         // t
    console.log( f instanceof Fun );        // f
    console.log( f instanceof Object );     // t
//两种使用,如果是返回ture,如果不是返回false;
//注意:instanceof运算符右侧为构造函数,并且js中所有原型都来自Object构造函数。

JS解析器访问属性顺序
当访问实例 f 的属性或方法时,会先在当前实例对象 f 中查找,如果没有,则沿着__proto__继续向上寻找,如果找到最顶头的Object还是找不到,则会抛出undefined。如果在实例中找到,或某层原型中找到,就会读取并使用,同时停止向上找寻。
由此可见,解析器的解析顺序遵循就近原则,如果在最近的位置发现属性存在,便不会继续向上找寻。

原型的应用
数组去重:

Array.prototype.noRepeat = function(){
    var m = [];
    for(var i=0;i<this.length;i++){
        if(m.indexOf(this[i]) == -1){
            m.push(this[i]);
        }
    }
    return m;
}
var arr = [3,4,5,6,7,6,5,4,3,2,1];
var res = arr.noRepeat();
console.log(res);

var arr1 = ["a","b","c","b","a"];
var res1 = arr1.noRepeat();
console.log(res1);



function Parent(){

}
Parent.prototype.show = function(){
    console.log("哈哈哈");
}

function Child(){

}
for(var i in Parent.prototype){
    Child.prototype[i] = Parent.prototype[i];
}
Child.prototype.show = function(){
    console.log("hello");
}

var p = new Parent();
p.show();
console.log(p.name);

var c = new Child();
c.show();
console.log(c.name);



————————————————
版权声明:本文为CSDN博主「zyfacd」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zyfacd/article/details/104909948

vue非父子组件间的传值

前端达人

vue非父子组件传值的基本语法

创建一个新的vue对象
var newvue = new Vue()
    
触发事件
newvue.$emit('自定义事件名', 参数)
    
监听事件
newvue.on('自定义事件名', 触发方法名)
    
销毁事件
newvue.off('自定义事件名')

案例

放在html页面上即可显示,注意要引入vue

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <div>父组件</div>
    <div>
      <button @click='handle'>销毁事件</button>
    </div>
    <test-tom></test-tom>
    <test-jerry></test-jerry>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript">
    /*
      兄弟组件之间数据传递
    */
    // 提供事件中心
    var hub = new Vue();

    Vue.component('test-tom', {
      data: function(){
        return {
          num: 0
        }
      },
      template: `
        <div>
          <div>TOM:{{num}}</div>
          <div>
            <button @click='handle'>点击</button>
          </div>
        </div>
      `,
      methods: {
        handle: function(){
          hub.$emit('jerry-event', 2);
        }
      },
      mounted: function() {
        // 监听事件
        hub.$on('tom-event', (val) => {
          this.num += val;
        });
      }
    });
    Vue.component('test-jerry', {
      data: function(){
        return {
          num: 0
        }
      },
      template: `
        <div>
          <div>JERRY:{{num}}</div>
          <div>
            <button @click='handle'>点击</button>
          </div>
        </div>
      `,
      methods: {
        handle: function(){
          // 触发兄弟组件的事件
          hub.$emit('tom-event', 1);
        }
      },
      mounted: function() {
        // 监听事件
        hub.$on('jerry-event', (val) => {
          this.num += val;
        });
      }
    });
    var vm = new Vue({
      el: '#app',
      data: {

      },
      methods: {
        handle: function(){
          hub.$off('tom-event');
          hub.$off('jerry-event');
        }
      }
    });
  </script>
</body>
</html>
————————————————
版权声明:本文为CSDN博主「温柔的坚持」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43745003/article/details/104919633



使用layui实现的左侧菜单栏以及动态操作tab项

前端达人

首先说一下左侧菜单栏

点击查看原图

这是一个最基本的左侧菜单栏,实现的过程很简单,官方的说明文档就有,但是我在导入layer.js之后,直接复制这段官方代码到我的编辑器上时,发现页面是这样的:


20180301152527380.png

发现,绑定属性的菜单并没有下拉选项,这个问题在我导入layer.all.js之后解决了,而且发现如果是在页面的最上方导入的话也没有下拉选项,只有在html代码下面导入,才可以显示 ,不知道是什么原因

下面说重点,动态操作tab项

页面截图:

20180301152822865.png

tab项右键菜单:


20180301152903581.png

这里右键菜单的样式并没有做太多的美化。

html代码:(页面中关于引入js和css文件的部分被我省略了,还有要注意jQuery的引入顺序)

<div class="layui-tab layui-tab-card site-demo-button" style="position: relative;">
            <ul class="layui-nav layui-nav-tree layui-nav-side">
                <li class="layui-nav-item layui-nav-itemed">
                    <a href="javascript:;">默认展开</a>
                    <dl class="layui-nav-child">
                        <dd>
                            <a data-url="a" data-id="11" data-title="选项a" href="#" class="site-demo-active" data-type="tabAdd">选项a</a>
                        </dd>
                        <dd>
                            <a href="#" data-url="b" data-title="选项b"  data-id="22" class="site-demo-active" data-type="tabAdd">选项b</a>
                        </dd>
                        <dd>
                            <a href="">跳转</a>
                        </dd>
                    </dl>
                </li>
                <li class="layui-nav-item">
                    <a href="javascript:;">解决方案</a>
                    <dl class="layui-nav-child">
                        <dd>
                            <a href="">移动模块</a>
                        </dd>
                        <dd>
                            <a href="">后台模版</a>
                        </dd>
                        <dd>
                            <a href="">电商平台</a>
                        </dd>
                    </dl>
                </li>
                <li class="layui-nav-item">
                    <a href="#" data-url="c" data-title="选项c"  data-id="33" class="site-demo-active" data-type="tabAdd">产品c</a>
                </li>
                <li class="layui-nav-item">
                    <a href="">大数据</a>
                </li>
            </ul>

            <div class="layui-tab" lay-filter="demo" lay-allowclose="true" style="margin-left: 200px;">
                <ul class="layui-tab-title">
                </ul>
                <ul class="rightmenu" style="display: none;position: absolute;">
                    <li data-type="closethis">关闭当前</li>
                    <li data-type="closeall">关闭所有</li>
                </ul>
                <div class="layui-tab-content">
                </div>
            </div>

        </div>
js代码:

layui.use('element', function() {
            var $ = layui.jquery;
            var element = layui.element; //Tab的切换功能,切换事件监听等,需要依赖element模块

            //触发事件
            var active = {
                //在这里给active绑定几项事件,后面可通过active调用这些事件
                tabAdd: function(url,id,name) {
                    //新增一个Tab项 传入三个参数,分别对应其标题,tab页面的地址,还有一个规定的id,是标签中data-id的属性值
                    //关于tabAdd的方法所传入的参数可看layui的开发文档中基础方法部分
                    element.tabAdd('demo', {
                        title: name,
                        content: '<iframe data-frameid="'+id+'" scrolling="auto" frameborder="0" src="'+url+'.html" style="width:100%;height:99%;"></iframe>',
                        id: id //规定好的id
                    })
                     CustomRightClick(id); //给tab绑定右击事件
                     FrameWH();  //计算ifram层的大小
                },
                tabChange: function(id) {
                    //切换到指定Tab项
                    element.tabChange('demo', id); //根据传入的id传入到指定的tab项
                }, 
                tabDelete: function (id) {
                element.tabDelete("demo", id);//删除
                }
                , tabDeleteAll: function (ids) {//删除所有
                    $.each(ids, function (i,item) {
                        element.tabDelete("demo", item); //ids是一个数组,里面存放了多个id,调用tabDelete方法分别删除
                    })
                }
            };

            //当点击有site-demo-active属性的标签时,即左侧菜单栏中内容 ,触发点击事件
            $('.site-demo-active').on('click', function() {
                var dataid = $(this);

                //这时会判断右侧.layui-tab-title属性下的有lay-id属性的li的数目,即已经打开的tab项数目
                if ($(".layui-tab-title li[lay-id]").length <= 0) {
                    //如果比零小,则直接打开新的tab项
                    active.tabAdd(dataid.attr("data-url"), dataid.attr("data-id"),dataid.attr("data-title"));
                } else {
                    //否则判断该tab项是否以及存在

                    var isData = false; //初始化一个标志,为false说明未打开该tab项 为true则说明已有
                    $.each($(".layui-tab-title li[lay-id]"), function () {
                        //如果点击左侧菜单栏所传入的id 在右侧tab项中的lay-id属性可以找到,则说明该tab项已经打开
                        if ($(this).attr("lay-id") == dataid.attr("data-id")) {
                            isData = true;
                        }
                    })
                    if (isData == false) {
                        //标志为false 新增一个tab项
                        active.tabAdd(dataid.attr("data-url"), dataid.attr("data-id"),dataid.attr("data-title"));
                    }
                }
                //最后不管是否新增tab,最后都转到要打开的选项页面上
                active.tabChange(dataid.attr("data-id"));
            });

            function CustomRightClick(id) {
                //取消右键  rightmenu属性开始是隐藏的 ,当右击的时候显示,左击的时候隐藏
                $('.layui-tab-title li').on('contextmenu', function () { return false; })
                $('.layui-tab-title,.layui-tab-title li').click(function () {
                    $('.rightmenu').hide();
                });
                //桌面点击右击 
                $('.layui-tab-title li').on('contextmenu', function (e) {
                    var popupmenu = $(".rightmenu");
                    popupmenu.find("li").attr("data-id",id); //在右键菜单中的标签绑定id属性

                    //判断右侧菜单的位置 
                    l = ($(document).width() - e.clientX) < popupmenu.width() ? (e.clientX - popupmenu.width()) : e.clientX;
                    t = ($(document).height() - e.clientY) < popupmenu.height() ? (e.clientY - popupmenu.height()) : e.clientY;
                    popupmenu.css({ left: l, top: t }).show(); //进行绝对定位
                    //alert("右键菜单")
                    return false;
                });
            }

            $(".rightmenu li").click(function () {

                //右键菜单中的选项被点击之后,判断type的类型,决定关闭所有还是关闭当前。
                if ($(this).attr("data-type") == "closethis") {
                    //如果关闭当前,即根据显示右键菜单时所绑定的id,执行tabDelete
                    active.tabDelete($(this).attr("data-id"))
                } else if ($(this).attr("data-type") == "closeall") {
                    var tabtitle = $(".layui-tab-title li");
                    var ids = new Array();
                    $.each(tabtitle, function (i) {
                        ids[i] = $(this).attr("lay-id");
                    })
                    //如果关闭所有 ,即将所有的lay-id放进数组,执行tabDeleteAll
                    active.tabDeleteAll(ids);
                }

                $('.rightmenu').hide(); //最后再隐藏右键菜单
            })
            function FrameWH() {
                var h = $(window).height() -41- 10 - 60 -10-44 -10;
                $("iframe").css("height",h+"px");
            }

            $(window).resize(function () {
                FrameWH();
            })
        });

tab项是放在<div class="layui-tab" lay-filter="demo" lay-allowclose="true" style="margin-left: 200px;"> 这个div中的,其中有一个重要的属性lay-filter,在js中调用的tabAdd,tabDelete等多种方法都携带了这个参数,我对此的理解是相当于一个判断拦截功能,将tab项放在lay-filter=‘demo’的div中。可以借助该参数,完成指定元素的局部更新。

其中还有关于element的操作,var element = layui.element
element模块的实例
返回的element变量为该实例的对象,携带一些用于元素操作的基础方法,我们就是用这些方法进行tab项的新增和删除还有切换。

这是element 中的tabAdd方法,其中的content可以是一个iframe页面,在此例中,我就是传递了一个简单的页面,这就实现了不同页面间的一些切换。

element.tabAdd('demo', {
  title: '选项卡的标题'
  ,content: '选项卡的内容' //支持传入html
  ,id: '选项卡标题的lay-id属性值'
});

————————————————
版权声明:本文为CSDN博主「nb7474」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/nb7474/article/details/79413460/

JavaScript拖拽效果

前端达人

要实现JavaScript的拖拽效果,首先我们需要知道事件对象几个有关于实现拖拽效果的坐标

获取事件对象 var e = e || window.event;



根据需求需要用到的拖拽效果的坐标



clientX:鼠标点击位置相对于浏览器可视区域的水平偏移量(不会计算水平滚动的距离)



clientY:鼠标点击位置相对于浏览器可视区域的垂直偏移量(不会计算垂直滚动条的距离)



offsetX:鼠标点击位置相对于触发事件对象的水平距离



offsetY:鼠标点击位置相对于触发事件对象的垂直距离



pageX:鼠标点击位置相对于网页左上角的水平偏移量,也就是clientX加 上水平滚动条的距离



pageY:鼠标点击位置相对于网页左上角的垂直平偏移量,也就是clientY加上垂直滚动条的距离



offsetLeft:如果父元素中有定位的元素,那么就返回距离当前元素最近的定位元素边缘的距离



offsetTop:如果父元素中没有定位元素,那么就返回相对于body左边缘距离



获取元素自身大小:offsetWidth和offsetHeight / clientWidth和clientHeight



offsetWidth和clientWidth的区别:就是offsetWidth包含边框,clientWidth不包含边框



实现拖拽需要用到:clientWidth、clientHeight、clientX、clientY、offsetLeft、offsetTop


首先搭建好html结构和css样式


 <div class="wrap">
        <div class="cover">

        </div>
    </div>

* {
            margin: 0;
            padding: 0;
        }

        .wrap {
            width: 500px;
            height: 500px;
            border: 1px solid deeppink;
            position: relative;
            margin: 50px auto;
        }

        .cover {
            width: 150px;
            height: 150px;
            background: rgba(200, 7, 99, 0.5);
            display: none;
            position: absolute;
            left: 0;
            top: 0;
            cursor: move;
        }
注意:需要给大盒子和小盒子进行定位:子绝父相
接下来就JavaScript代码

<script>
    var wrap = document.querySelector(".wrap");
    var cover = document.querySelector(".cover");
    wrap.onmouseover = function() {
        cover.style.display = "block";
        wrap.onmousemove = function(e) {
            var e = e || window.event;
            var x1 = e.clientX;
            var y1 = e.clientY;
//这里获取到的e.clientX和e.clientY,可以看情况和需求改为e.pageX和e.pageY             
            var halfWidth = cover.clientWidth / 2;
            var halfHeight = cover.clientHeight / 2;
            var wrapLeft = wrap.offsetLeft;
            var wrapTop = wrap.offsetTop;
            var l = x1 - wrapLeft - halfWidth;
            var t = y1 - wrapTop - halfHeight;

            if (l <= 0) {
                l = 0
            }
            if (l >= wrap.clientWidth - cover.clientWidth) {
                l = wrap.clientWidth - cover.clientWidth
            }
            if (t <= 0) {
                t = 0
            }
            if (t >= wrap.clientHeight - cover.clientHeight) {
                t = wrap.clientHeight - cover.clientHeight
            }
            cover.style.left = l + "px";
            cover.style.top = t + "px"
        }
    }
    wrap.onmouseout = function() {
        cover.style.display = "none";
    }
</script>

  var halfWidth = cover.clientWidth / 2;
            var halfHeight = cover.clientHeight / 2;
            var wrapLeft = wrap.offsetLeft;
            var wrapTop = wrap.offsetTop;
            var l = x1 - wrapLeft - halfWidth;
            var t = y1 - wrapTop - halfHeight;
            //限制范围
             if (l <= 0) {
                l = 0
            }
            if (l >= wrap.clientWidth - cover.clientWidth) {
                l = wrap.clientWidth - cover.clientWidth
            }
            if (t <= 0) {
                t = 0
            }
            if (t >= wrap.clientHeight - cover.clientHeight) {
                t = wrap.clientHeight - cover.clientHeight
            }
注意:这里要限制小盒子在大盒子之间移动的范围,左上角的限制,当小盒子超出范围时,将0赋值给l和t。右下角小盒子移动的范围在大盒子宽度减去小盒子的宽度。
其中为了使鼠标一直处于小盒子(cover)的最中间,需要减去小盒子宽度的一半。
再减去大盒子距离页面左边的边距和上边的边距就可以得到坐标

只要鼠标移入大盒子中,就能直接拖拽小盒子,并且鼠标一直处于小盒子的最中间。这样便完成了简单的拖拽效果。

20200315200118747.png
20200315200118747.png


————————————————
版权声明:本文为CSDN博主「_kaze」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/luffy_999/article/details/104884538

响应式布局如何实现

前端达人

css面试题@响应式布局如何实现

1为什么要使用响应式布局

响应式布局可以让网站同时适配不同分辨率和不同的手机端,让客户有更好

的体验。



2如何实现

方案一:百分比布局

利用对属性设置百分比来适配不同屏幕,注意这里的百分比是相对于父元素; 能够设置的属性有width,、height、padding、margin,其他属性比如border、 font-size不能用百分比来设置的

由于没办法对font-size进行百分比设置,所以用的最多就是对图片和大块布局进行百分比设置。



方案二:使用媒体查询 (CSS3@media 查询)

利用媒体查询设置不同分辨率下的css样式,来适配不同屏幕。

媒体查询相对于百分比布局,可以对布局进行更细致的调整,但需要在每个分辨率下面都写一套css样式。

该布局的话适用于简单的网页,可以使移动端和pc端使用一套网址。从而节约成本。也方便后期的维护,bootcss就是用了CSS3的media来实现响应的 但是相对于复杂的网页就不适合了(如:淘宝,京东)等等



方案三.rem 响应式布局

rem布局的原理

rem:相对于根元素(即html元素)font-size计算值的倍数。

如 html的font-size为100px;那么2rem就为200px。

通俗的来讲的话rem就是通过JavaScript来获取页面的宽度,从而动态的计算rem。这样就会使不同分辨率下展现出相同的效果。

//代码展示

css面试题@响应式布局如何实现
1为什么要使用响应式布局
响应式布局可以让网站同时适配不同分辨率和不同的手机端,让客户有更好
的体验。

2如何实现
方案一:百分比布局
利用对属性设置百分比来适配不同屏幕,注意这里的百分比是相对于父元素; 能够设置的属性有width,、height、padding、margin,其他属性比如border、 font-size不能用百分比来设置的
由于没办法对font-size进行百分比设置,所以用的最多就是对图片和大块布局进行百分比设置。

方案二:使用媒体查询 (CSS3@media 查询)
利用媒体查询设置不同分辨率下的css样式,来适配不同屏幕。
媒体查询相对于百分比布局,可以对布局进行更细致的调整,但需要在每个分辨率下面都写一套css样式。
该布局的话适用于简单的网页,可以使移动端和pc端使用一套网址。从而节约成本。也方便后期的维护,bootcss就是用了CSS3的media来实现响应的 但是相对于复杂的网页就不适合了(如:淘宝,京东)等等

方案三.rem 响应式布局
rem布局的原理
rem:相对于根元素(即html元素)font-size计算值的倍数。
如 html的font-size为100px;那么2rem就为200px。
通俗的来讲的话rem就是通过JavaScript来获取页面的宽度,从而动态的计算rem。这样就会使不同分辨率下展现出相同的效果。
//代码展示
上述代码中 7.5为动态的值,根据设计图的宽度进行动态的改变。window.onresize的作用是:当页面的宽度或高度发生改变时,再次进行调用rem函数。

方案四.vw 响应式布局
vm,vh相应式布局通俗来讲就是有一点类似百分比布局 将页面的宽和高分别分为100份 1vm就是为宽度的百分之一,同理1vh及为高度的百分之一。段手机端用的最多就是这个方法,能保持不同屏幕下元素显示效果一致,也不用写多套样式。

方案五.flex 弹性布局
flex就是利用css3中的弹性盒子向下兼容到IE10
利用flex属性来适配不同屏幕, 该方法一般都会结合rem布局来写移动端页面

————————————————
版权声明:本文为CSDN博主「姚先生丶」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/listStyleScript/article/details/104862009

如何在网页前端里可视化你的知识图谱

前端达人

如何在网页前端里可视化你的知识图谱
最近费尽千辛万苦构造了一份可以用(大概)的知识图谱,并且把要利用知识图谱做的领域命名实体识别和一些推荐的功能做成Web版的demo,顺带想实现一些可视化知识图谱的功能。

(凭啥知识图谱就只能在Neo4j里自嗨,不能来前端show一下,歧视吗(¬_¬))

找了做前端图表展示的开源库,D3.js和Echarts都能做,我拿Echarts实现了一下功能,先看一下在现在项目里一个基于知识图谱查询的实际效果:
20200314114824402.png

接下里看看如何的实现:

  1. 首先在本地下载Echarts相关的js文件,在线引用也可以,html文件里如下引用:
 <script src="/static/js/echarts.common.min.js"></script>   
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts@4.5.0/dist/echarts.min.js"></script>
给要展示的图准备一个Dom:

<!-- 为ECharts准备一个具备大小的Dom -->
    <div class = "col-md-12">
        <div class="panel panel-default ">
            <header class="panel-heading">
                关系图 :
            </header>
            <div class = "panel-body ">
                <div id="graph" style="width: 100%;height:600px;"></div>
            </div>
        </div>
    </div>


3.设置好节点和链接关系,这里为了简单手写了一个苹果梨子和水果之间的关系,项目里采用Django框架的交互读取查询的结果放入节点(data)和链接(links)里面了:

data = [
        {name:'苹果',category:1,id:0},
        {name:'梨子',catagory:1,id:1},
        {name:'水果',category:2,id:2}
        ]
    links = [
        {source:0,target:2,category:0,value:'属于',symbolSize:10},
        {source:1,target:2,category:0,value:'属于',symbolSize:10}
    ]


置Echarts图:

var myChart = echarts.init(document.getElementById('graph'));

    option = {
        title: {
            text: ''
        },
        tooltip: {},
        animationDurationUpdate: 1500,
        animationEasingUpdate: 'quinticInOut',
        label: {
            normal: {
                show: true,
                textStyle: {
                    fontSize: 12
                },
            }
        },
        legend: {
            x: "center",
            show: false
        },
        series: [

            {
                type: 'graph',
                layout: 'force',
                symbolSize: 45,
                focusNodeAdjacency: true,
                roam: true,
                edgeSymbol: ['none', 'arrow'],
                categories: [{
                    name: '查询实体',
                    itemStyle: {
                        normal: {
                            color: "#009800",
                        }
                    }
                }, {
                    name: 'instance',
                    itemStyle: {
                        normal: {
                            color: "#4592FF",
                        }
                    }
                }, {
                    name: 'class',
                    itemStyle: {
                        normal: {
                            color: "#C71585",
                        }
                    }
                }],
                label: {
                    normal: {
                        show: true,
                        textStyle: {
                            fontSize: 12,
                        },
                    }
                },
                force: {
                    repulsion: 1000
                },
                edgeSymbolSize: [4, 50],
                edgeLabel: {
                    normal: {
                        show: true,
                        textStyle: {
                            fontSize: 10
                        },
                        formatter: "{c}"
                    }
                },
                data: data,
                links: links,
                lineStyle: {
                    normal: {
                        opacity: 0.9,
                        width: 1.3,
                        curveness: 0,
                        color:"#262626",
                    }
                }
            }
        ]
    };
    // 使用刚指定的配置项和数据显示图表。
    myChart.setOption(option);
这样就成功实现了一个简单的图谱可视化:

20200314115929363.png



————————————————
版权声明:本文为CSDN博主「游离态GLZ不可能是金融技术宅」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37477357/article/details/104857495


JavaWeb项目之实现用户注册、登录与预约功能

前端达人

JavaWeb项目之实现用户注册、登录与预约功能


  • 四:效果展示
  • 一:项目需求

    1.实现注册与登录功能:
    要求用到验证码,登录后该出不再显示登录与注册,而是显示用户名。
    2.实现预约功能:
    实现“运动”与“学习”两方面的邀约功能,并将邀约数据保存到数据库中,数据库使用Mysql。
    运动可以邀约:篮球、足球、乒乓球等
    学习可以邀约:自习、辅导等

    二:总体概述

    在正式开始编码之前,需要先导入相关jar包并配置好相关的配置文件,同时也需要导入前端给的页面代码。接着是建立好相应的数据库结构,并初步构建好三层架构的想法思路。

    20200313144400508.png

   20200313144131716.png

20200313144239593.png



三:代码分析

1.登录功能

web层

20200313132713991.png


  • 20200313133324242.png

  • service层

  • 2020031313345737.png

  • dao层

  • 20200313133603198.png

  • 然后在这里写一下对于验证码处理和点击图片更换验证码功能的一些细节。
    如下图所示,为了保证servlet层能够正确接收到界面所展示的验证码信息,同时因为session对象是项目自生成的,所以我直接获取session对象并以类似于键值对的形式将页面验证码信息存入session中。

  • 接下来是jsp页面对于验证码展示的一些处理

  • 20200313135922196.png

  • 20200313135956797.png

在这里,因为点击验证码更换操作需要用到js,所以我百度得到了上图这样一串代码。其中时间戳的作用是通过改变每次请求的时间参数来获得刷新效果,即改变url中的响应头信息。

2.注册功能
事实上,有了登录功能的实现,注册功能的代码与其都是大同小异的。最大的不同应该就是Dao层执行的操作不同

20200313142134901.png

3.预约功能

预约功能的实现更是与注册功能的实现基本一致。所不同的应该是jsp页面对单选框输入的设置。

20200313142805359.png


四:效果展示

点击查看原图




日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档