前端及开发文章及欣赏

前端学习之JavaScript DOM以及DOM操作的基础知识

前端达人

在了解了javascript的语言基础和特性后

javascript真正大放光彩的地方来了——这就是javascript DOM


Javascript DOM
DOM(Document Object Model),文档对象模型。

是W3C组织推荐的处理可扩展标记语言(HTML或者XML)的标准编程接口;W3C已经定义了一系列DOM接口,通过这些DOM接口可以改变网页的内容、结构和样式。

简单的说就是一套操作文档内容的方法。

需要注意的是,我们需要把DOM当作一个整体,不能分割看待,即DOM(文档对象模型)是一套操作文档内容的方法。


  • 文档:一个页面就是一个文档,DOM中使用document表示
  • 元素:页面中的所有标签都是元素,DOM中使用element表示
  • 节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM中使用node表示

DOM把以上内容看作都是对象

<!DOCTYPE html>
<html>
<head>
    <title>Shopping list</title>
    <meta charset="utf-8">
</head>
<body>
<h1>What to buy</h1>
<p id="buy" title="a gentle reminder">Don't forget to buy this stuff</p>
<ul id="purchases">
    <li>A tin od beans</li>
    <li>Cheese</li>
    <li>Milk</li>
</ul>
</body>
</html>



用树表示这个网页的结构:

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2ktYmV0YS8xODQ2ODAyLzIwMTkxMi8xODQ2ODAyLTIwMTkxMjIzMTcxMDI5MTY1LTExNTE0OTgxMDMucG5n.jpg

1、获取DOM四种基本方法
1、getElementById()

2、getElementsByTagname()

3、getAttribute()

4、setAttribute()

 

常用的两种解析:

1. getElementById():

参数:元素的ID值。 (元素节点简称元素) 
返回值:一个有指定ID的元素对象(元素是对象) 
注:这个方法是与document对象相关联,只能由document对象调用。 
用法:document.getElementById(Id) 

例:

<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="time">2020-04-16</div>
    <script>
        // 1. 因为我们文档页面从上往下加载,所以先得有标签 所以我们script写到标签的下面
        // 2. get 获得 element 元素 by 通过 驼峰命名法 
        // 3. 参数 id是大小写敏感的字符串
        // 4. 返回的是一个元素对象
        var timer = document.getElementById('time');
        console.log(timer);
        console.log(typeof timer);
        // 5. console.dir 打印我们返回的元素对象 更好的查看里面的属性和方法
        console.dir(timer);
    </script>
</body>

</html>




看一下控制台打印的是什么

20200416221227181.png


可以看到 console.log(timer)打印出来的是整个div标签

timer类型是个对象

 

2. getElementsByTagName():

参数:元素名
返回值:一个对象数组。这个数组里每个元素都是对象,每个对象分别对应着文档里给定标签的一个元素。
注:这个方法可和一般元素关联。这个方法允许我们把通配符当作它的参数,返回在某份html文档里总共有多少个元素节点。
用法:element.getElementsByTagName(TagName) 

例:

var items=document.getElementsByTagName("li");
items.length;//3
document.getElementsByTagName(“*”);//12
 

 

2、事件基础
3.1 事件概述
JavaScript使我们有能力创建动态页面,而事件是可以被JavaScript侦测到的行为。

简单理解:触发——>响应机制

网页中每个元素都可以产生某些可以触发JavaScript的事件,例如,我们可以在用户点击某按钮产生一个事件,然后去执行某些操作

3.2 事件三要素
事件源 、事件类型、事件处理程序,我们也称为事件三要素

(1) 事件源 事件被触发的对象   谁  
(2) 事件类型  如何触发 什么事件 比如鼠标点击(onclick) 还是鼠标经过 还是键盘按下
(3) 事件处理程序  通过一个函数赋值的方式 完成

代码实例

<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <button id="btn">唐伯虎</button>
    <script>
        // 点击一个按钮,弹出对话框
        // 1. 事件是有三部分组成  事件源  事件类型  事件处理程序   我们也称为事件三要素
        //(1) 事件源 事件被触发的对象   谁  按钮
        var btn = document.getElementById('btn');
        //(2) 事件类型  如何触发 什么事件 比如鼠标点击(onclick) 还是鼠标经过 还是键盘按下
        //(3) 事件处理程序  通过一个函数赋值的方式 完成
        btn.onclick = function() {
            alert('点秋香');
        }
    </script>
</body>

</html>


运行结果

20200416223238828.png

3.3 执行事件的步骤

1、获取事件源

2、注册事件(绑定事件)

3、添加事件处理程序(采取函数赋值形式)

 

代码实战


        


<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div>123</div>
    <script>
        // 执行事件步骤
        // 点击div 控制台输出 我被选中了
        // 1. 获取事件源
        var div = document.querySelector('div');
        // 2.绑定事件 注册事件
        // div.onclick 
        // 3.添加事件处理程序 
        div.onclick = function() {
            console.log('我被选中了');

        }
    </script>
</body>

</html>



常用的DOM事件
onclick事件---当用户点击时执行
onload事件---当用户进入时执行
onunload事件---用用户离开时执行
onmouseover事件---当用户鼠标指针移入时执行
onmouseout事件---当用户鼠标指针移出时执行
onmousedown事件---当用户鼠标摁下时执行
onmouseup事件---当用户鼠标松开时执行
 
————————————————
版权声明:本文为CSDN博主「那是我呐」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42402867/article/details/105567787

【CSS基础学习】CSS的三大特性

前端达人

文章目录


CSS有三大特性,分别是 继承性,层叠性,优先级。CSS的主要特征是继承性,这里先讲解继承性。

继承性

继承性的使用说明

继承性的描述:
继承性是指被包在内部的标签将拥有外部标签的样式性,即子元素可以继承父类的属性。
例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div{
            color: blue;
        }
    </style>
</head>
<body>
    <div>父元素
        <div>子元素
            <p>我依旧是子元素</p>
        </div>
    </div>
</body>
</html>



效果如下:

有图可见,被div包裹住的元素,都具有了div的css样式属性,这被我们称为继承性。

在CSS中以,text-,font-,line-开头的属性都是可以继承的。

CSS继承的局限性
并不是所有的CSS属性都可以被继承的,以下就不具有继承性:

a标签的字体颜色不会被继承,a标签的字体颜色是不会改变的,可以通过页面的的F12可以查看到,a标签是有一个默认的color:-webkit-link;字体颜色属性,所以父元素设置颜色是不能发生改变a标签字体的颜色。
h标签的字体的大小也是不能被继承的,如下代码给父元素在设置一个字体属性20px,再添加一个h标签,在浏览器中可以发现h标签中字体的大小是不会发生改变的,因为h标签中有一个默认的font-size:1.5em;字体大小属性。
div标签的高度如果不设置由内容来绝对(没有内容高度未0),宽度默认由父元素继承过来
边框属性
外边距属性
内边距属性
背景属性
定位属性
布局属性
元素宽高属性
层叠性
层叠性的使用说明
层叠性的表述
所谓层叠性是指多种CSS样式的叠加,例如,当使用内嵌式CSS样式表定义p标记字号大小为12像素,ID选择器定义p标记颜色为红色,那么段落文本将显示为12像素红色,即这两种样式产生了叠加。
例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        p{
            font-size: 32px;
        }
    </style>
</head>
<body>
            <p style="color: blue;">我这里体现了层叠性呀</p>
</body>
</html>



使用结论
由于内容有限,但是结论是一定的,所以我直接给出结论:

若多个选择器定义的样式不冲突,则元素应用所有选择器定义的样式。
若多个选择器定义的样式发生冲突(比如:同时定义了字体颜色属性),则CSS按照选择器的优先级,让元素应用优先级搞得选择器样式。
CSS定义的选择器优先级从高到低为:行内样式–>ID样式–>类样式–>标记样式。
如若想直接定义使用哪个样式,不考虑优先级的话,则使用!important,把这个加在样式后面就行了。
优先级
定义CSS样式时,经常出现两个或更多规则应用在同一个元素上,这时就会出现优先级的问题。层叠性和选择器的圈中有很大的关系。

优先级的使用说明
权重分析:

内联样式:如:style="",权重为1000。
ID选择器,如:#content,权重为100。
类,伪类和属性选择器,如.content,权重为10。
标签选择器和伪元素选择器,如div p,权重为1。
继承样式,权重为0。
将基本选择器的权重相加之和,就是权重大小,值越大,权重越高。
计算权重方法
数标签:先数权重最高的标签,然后数第二高权重的标签,以此类推,就会生成一个数组,里面包含四个数字。
比如(0,0,0,0)分别对应(行内式个数,id选择器个数,类选择器个数,标签选择器个数)
然后两个选择器通过对别四个数字的大小,确定权重关系。
例:
#box ul li a.cur有1个id标签,1个类,3个标签,那么4个0就是(0,1,1,3)
.nav ul .active .cur有0个id,3个类,1个标签,那么4个0就是(0,0,3,1)
例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .p1{
            color: blue;
        }
        #p1{
            color: red;
        }
    </style>
</head>
<body>
            <p id="p1" class="p1">我们来试一下优先级</p>
</body>
</html>


先推测一波,因为前面讲到了ID选择器的权重是大于类选择器的,所以这里颜色应该为red。
效果如下:

推测正确!优先级GET!


vue,vant,使用过程中 Swipe 轮播自定义大小遇到的坑

前端达人

今天讲一下使用vant Swipe 轮播控件过程中遇到的问题

主要是使用swiper自定义的大小的时候,宽度适应不同分辨率的移动设备

适应宽度的同时还需控件的正常使用


先看一下需要实现的功能,

微信截图_20200417142351.png

微信截图_20200417142429.png

一个简单的轮播图,但是每个轮播的宽度需要低于100%,使第二个轮播的van-swipe-item可以展示到第一个位置一部分



这时我们再去vant的文档查看一下控件

微信截图_20200417142821.png


刚好有一个自定义控件大小的可以使用,完美解决了我们的问题


当我们使用控件之后


 <van-swipe :loop="false"  @change="onChange" :width="350">
        <van-swipe-item v-bind:id="item0"><div class="swipe0">
            <div class="contion">

                <p class="title">家中有事,申请请假一天</p>
                <p class="title1"><span class="rice"></span>部门经理核审中</p>
                <p class="time">03.8 &nbsp;&nbsp;&nbsp; 14.25</p>
                <p class="type">放假申请</p>
            </div>
            <img src="../../assets/images/index/xx/fangjia.png">

        </div></van-swipe-item>
        <van-swipe-item ><div class="swipe1"></div></van-swipe-item>
        <van-swipe-item ><div class="swipe2"></div></van-swipe-item>
        <template #indicator>
            <div class="custom-indicator">
                {{ current + 1 }}/3
            </div>
        </template>
    </van-swipe>



发现功能可以使用,但是再 iPhone8/7 plus  以及iPhone5/se 等分辨率下出现了宽度固定而不适应的情况,

微信截图_20200417143329.png

微信截图_20200417143349.png


简单来说,我们把van-swipe-item宽度控制在了80% 第二个van-swipe-item自然可以展示出来一部分

但是当滑到第二页的时候 由于第一页的宽度还是80% 所以就出现了这样的情况,所以我打算采用

监听 change 事件

动态的改变 滑动到第几页的时候 把当页的宽度变为80% 其他页保持不变,


于是

 <van-swipe :loop="false"  @change="onChange" >
        <van-swipe-item v-bind:id="item0"><div class="swipe0">
            <div class="contion">

                <p class="title">家中有事,申请请假一天</p>
                <p class="title1"><span class="rice"></span>部门经理核审中</p>
                <p class="time">03.8 &nbsp;&nbsp;&nbsp; 14.25</p>
                <p class="type">放假申请</p>
            </div>
            <img src="../../assets/images/index/xx/fangjia.png">

        </div></van-swipe-item>
        <van-swipe-item v-bind:id="item1"><div class="swipe1"></div></van-swipe-item>
        <van-swipe-item v-bind:id="item2"><div class="swipe2"></div></van-swipe-item>
        <template #indicator>
            <div class="custom-indicator">
                {{ current + 1 }}/3
            </div>
        </template>
    </van-swipe>





首先 我们为每个swipe-item添加id



 data(){
            return {
                android: true,
                ios: true,
                iphoneX: true,
                current: 0,
                item0:'item0',
                item1:'item1',
                item2:'item2',
            }
        },
        mounted(){

        },
        methods: {
            onChange(index){
                console.log('当前 Swipe 索引:' + index);
                if(index==1){
                    var div =document.getElementById("item0").style.setProperty('width', '10rem', 'important');
                    var div1 =document.getElementById("item1").style.setProperty('width', '9.3333333rem', 'important');
                    var div2 =document.getElementById("item2").style.setProperty('width', '9.3333333rem', 'important');
                } else  if(index==2){
                    var div1 =document.getElementById("item1").style.setProperty('width', '10rem', 'important');
                    var div0 =document.getElementById("item0").style.setProperty('width', '10rem', 'important');
                    var div2 =document.getElementById("item2").style.setProperty('width', '9.3333333rem', 'important');
                } else  if(index==0){
                    var div =document.getElementById("item2");
                    var div0 =document.getElementById("item0").style.setProperty('width', '9.3333333rem', 'important');
                    var div1 =document.getElementById("item1").style.setProperty('width', '9.3333333rem', 'important');
                }
            },



此外,监听滑动事件,根据滑动到第几页 更改当前页面的宽度,


这样就解决了




Swipe自定义宽度下,同时适应不同分辨率的情况


兰兰设计:前端达人





Emscripten教程之emcc编译命令

seo达人

语法


emcc [options] file ...

这个输入文件file,既可以是clang可以编译的C/C++语言,也可以是二进制形式的llvm bitcode或者人类可读形式的llvm assembly文件。

参数

大部分clang或者gcc的选项(option)都是可以工作的,比如:

# 显示信息 emcc --help # 显示编译器版本信息 emcc --version

如果想看当前Emscripten中clang版本支持的全部选项列表,可以直接使用命令:
clang --help.

emcc修改的或者emcc中新的选项列在下面:

首先是一些编译优化flag,它们-O0,-O1,-O2,-Os,-Oz,-O3。

-O0:
不进行编译优化(这是默认情况)。当你刚开始移植项目是推荐使用它,因为它会包含许多断言。

-O1:
简单优化。推荐你在既想缩短编译时间又想编译优化时使用。它毕竟比-O2级别的优化编译起来快多了。它会进行asm.js和llvm的-O1进行优化,它会relooping,会删除运行时断言和C++异常捕获,它也会使得-s ALIASING_FUNCTION_POINTERS=1。

想要C++异常捕获重新可用,请设置:-s DISABLE_EXCEPTION_CATCHING=0。

-O2:
和-O1类似,不过多了JavaScript级别的优化以及一些llvm -O3的优化项。当你想发布项目的时候,推荐使用本级别优化。

-O3:
和-O2类似,不过比-O2又多了一些JavaScript优化,而且编译时间明显比-O2长。这个也推荐在发布版本的时候使用。

-Os:
和-O3类似,不过增加了额外的优化以减小生成的代码体积,代价是比-O3性能差一点。-Os优化会同时影响llvm bitcode 和JavaScript文件的生成。

-Oz:
和-Os类似,不过进一步减小了代码体积。

-s OPTION=VALUE
传给编译器的所有涉及到JavaScript代码生成的选项。选项列表,请见settings.js

对于某个选项的值,不仅可以直接在emcc命令行里面设定,也可以把他们写成json文件。比如下面,就是将DEAD_FUNCTIONS选项的值放到了path/to/file文件里,emcc里面传这个文件的路径。

-s DEAD_FUNCTIONS=@/path/to/file
note: 1、文件内容可以是:["_func1","_func2"]; 2、文件路径必须是绝对的,不能是相对的。

-g:
这是保留调试信息flag。

  • 如果只是编译到bitcode,那就和clang和gcc中的-g一样。
  • 如果是要编译到JavaScript,-g就等于-g3。

-g<level>
控制打印的调试信息数量,每一个level都是在前一个level的基础上编译的:

  • -g0:不保留调试信息。
  • -g1:保留空格,不压缩。
  • -g2:保留函数名。
  • -g3:保留变量名,与-g同。变量名一般不是必须编译后保留的,但是如果保留了,可以推断变量的目的,对吧。
  • -g4:保留llvm 调试信息,这是能调试的最高级别。
note:
优化级别越高,编译时间越长

--profiling:

--profiling-funcs:

--tracing:
启用Emscripten的tracing API。

--emit-symbol-map:

--js-opts<level>:
允许JavaScript优化,有两个值:
0:不允许JavaScript优化器允许;
1:使用JavaScript优化器。
通常用不到我们设置这一项, 因为设置-O后面的level的时候,这个项就能顺便取到一个合适的值。

note:
有些选项会重写这个flag的值,比如EMTERPRETIFY, DEAD_FUNCTIONS, OUTLINING_LIMIT, SAFE_HEAP 和 SPLIT_MEMORY会将js-opts=1,因为他们依赖js优化器。

--llvm-opts<level>:
启用llvm优化。它的取值有有:

  • 0:不使用llvm优化
  • 1:llvm -O1优化
  • 2:llvm -O2优化
  • 3:llvm -O3优化

和--js-opts<level>一样,通常用不到我们设置这一项, 因为设置-O后面的level的时候,这个项就能顺便取到一个合适的值。

--llvm-lto<level>:
启用llvm 连接时 优化。可以取值0,1,2,3。

--closure <on>:
运行压缩编译器(Closure Compiler),可能的取值有,0,1,2:

  • 0:是不启用压缩编译器。
  • 1:启用。
  • 2:启用。

--pre-js <file>
生成代码前,指定一个要把内容添加进来的文件。

--post-js <file>
生成代码后,指定一个要把内容添加进来的文件。

--embed-file <file>
指定一个带路径的文件嵌入到编译生成的js代码里。路径是相对于编译时的当前路径。如果传的是一个目录,则目录下所有文件的内容都会被嵌入到将来生成的js代码中。

--preload-file <name>
异步运行编译代码前,指定一个预加载的文件。路径是相对于编译时的当前路径。如果传的是一个目录,则目录下所有文件的内容都会被预加载到一个.data文件中。

--exclude-file <name>
从 –embed-file and –preload-file后面的目录中排除一些文件,支持使用通配符*。

--use-preload-plugins
告诉文件打包器当文件加载时,运行预加载插件。它用来执行诸如使用浏览器解码器解码图片和音频等。

--shell-file <path>
指定要生成HTML的模板文件。

--source-map-base <base-url>

--minify 0
等于-g1。

--js-transform <cmd>
优化之前,生成代码之后,设定这一条命令。这条命令可以让你修改JavaScript代码。之后,编译器会将修改的和未修改的一起进行编译优化。

--bind
启用bingdings编译源代码。bingings是Emscripten中连接C++和JavaScript代码的一类API。

--ignore-dynamic-linking
告诉编译器忽视动态链接,之后用户就得手动链接到共享库。

--js-library <lib>
定义除了核心库(src/library_*)以外的js库。

-v
打开详细输出。
这个设置为把-v传给clang,并且启用EMCC_DEBUG生成编译阶段的中间文件。它也会运行Emscripten关于工具链的内部的完整性检查。

tip: emcc -v是诊断错误的有用工具,不管你是否附加其他参数。

--cache

--clear-cache

--clear-ports

--show-ports

--save-bc PATH

--memory-init-file <on>
规定是否单独生成一个内存初始化文件。取值包括0和1.

  • 0:不单独生成.mem文件。
  • 1:单独生成.mem文件。

-Wwarn-absolute-paths
启用在-I和-L命令行指令中使用绝对路径的警告。这是用来警告无意中使用了绝对路径的。在引用非可移植的本地系统头文件时,使用绝对路径有时是很危险的。

--proxy-to-worker

--emrun
使生成的代码能够感知emrun命令行工具。当运行emran生成的应用程序时,这样设置就允许stdout、stderr和exit(returncode)被捕获。

--cpuprofiler
在生成的页面上嵌入一个简单的CPU分析器。使用这个来执行粗略的交互式性能分析。

--memoryprofiler
在生成的页面上嵌入内存分配跟踪器,使用它来分析应用程序Emscripten堆的使用情况。

--threadprofiler
在生成的页面上嵌入一个线程活动分析器。当进行多线程编译时,使用它来分析多线程应用程序。
--em-config

--default-obj-ext .ext

--valid-abspath path
设置一个绝对路径的白名单,以防止关于绝对路径的警告。

-o <target>
编译输出的文件格式。target可以取值为:

  • name.js:JavaScript文件;
  • name.html:HTML+js文件。把js单独生成是为了减小页面加载时间。
  • name.bc:llvm bitcode。这是默认值。
  • name.o:和上面一样。
note:
如果你用了--memory-init-file,则还会从js文件中再单独分出一部分代码为.mem文件。

-c
生成llvm bitcode代码,而不是JavaScript。

--separate-asm
把asm.js文件单独生成到一个文件中。这样可以减少启动时的内存加载。

--output_eol windows|linux
规定生成的文本文件的行尾,如果是–output_eol windows,就是windows rn行尾,如果是–output_eol linux,则生成Linux行尾的文本文件。

--cflags

环境变量


emcc会受到几个环境变量的影响,如下:

  • EMMAKEN_JUST_CONFIGURE
  • EMMAKEN_JUST_CONFIGURE_RECURSE
  • EMCONFIGURE_JS
  • EMCONFIGURE_CC
  • EMMAKEN_CXX
  • EMMAKEN_COMPILER
  • EMMAKEN_CFLAGS
  • EMCC_DEBUG

这几个里面比较有意思的是EMCC_DEBUG。比如,如果你在编译之前设置set EMCC_DEBUG=1,那么编译的时候会把编译过程的调试信息和编译各个阶段的中间文件输出到一个临时目录,这算是给开发者提供一些编译期间的帮助或者说调试信息吧。


Emscripten主题系列文章是emscripten中文站点的一部分内容。
第一个主题介绍代码可移植性与限制
第二个主题介绍Emscripten的运行时环境
第三个主题第一篇文章介绍连接C++和JavaScript
第三个主题第二篇文章介绍embind
第四个主题介绍文件和文件系统
第六个主题介绍Emscripten如何调试代码

vue + vuex + koa2开发环境搭建及示例开发

seo达人

写在前面

这篇文章的主要目的是学会使用koa框架搭建web服务,从而提供一些后端接口,供前端调用。
搭建这个环境的目的是: 前端工程师在跟后台工程师商定了接口但还未联调之前,涉及到向后端请求数据的功能能够走前端工程师自己搭建的http路径,而不是直接在前端写几个死数据。即,模拟后端接口。

当然在这整个过程(搭建环境 + 开发示例demo)中,涉及到以下几点知识点。
包括:

  • koa2的知识点
  • node的知识点
  • 跨域问题
  • fetch的使用
  • axios的使用
  • promise的涉及
  • vuex -> state、mutations、actions的使用

第一部分:环境搭建

vue + vuex环境

首先是vue + vue-router + vuex的环境。我们用vue-cli脚手架生成项目,会用vue的同学对这块应该很熟了。

// 全局安装脚手架工具 npm i vue-cli -g // 验证脚手架工具安装成功与否 vue --version // 构建项目 vue init webpack 项目名 // 测试vue项目是否运行成功 npm run dev

因为脚手架生成的vue项目不包含vuex,所以再安装vuex。

// 安装vuex npm i vuex --save

koa2环境

前端项目构建好了,就开始构建我们的后端服务。

首先在你的开发工具(不管是webstorm还是sublime)里新建一个目录,用来搭建基于koa的web服务。

在这里,我们不妨给这个目录起名为koa-demo。

然后执行:

// 进入目录 cd koa-demo // 生成package.json npm init -y // 安装以下依赖项 npm i koa npm i koa-router npm i koa-cors

安装好koa和两个中间件,环境就算搭建完成了。

第二部分:示例开发

搭建环境是为了使用,所以我们立马来写一个demo出来。
demo开发既是一个练习如何在开发环境中写代码的过程,反过来,也是一个验证环境搭建的对不对、好不好用的过程。

后端接口开发

本例中,后端我们只提供一个服务,就是给前端提供一个返回json数据的接口。代码中包含注释,所以直接上代码。

server.js文件

 // server.js文件 let Koa = require('koa'); let Router = require('koa-router'); let cors = require('koa-cors'); // 引入modejs的文件系统API let fs = require('fs'); const app = new Koa(); const router = new Router(); // 提供一个/getJson接口 router
    .get('/getJson', async ctx => { // 后端允许cors跨域请求 await cors(); // 返回给前端的数据 ctx.body = JSON.parse(fs.readFileSync( './static/material.json'));

    }); // 将koa和两个中间件连起来 app.use(router.routes()).use(router.allowedMethods()); // 监听3000端口 app.listen(3000);

这里面用到了一个json文件,在'./static/material.json'路径,该json文件的代码是:

// material.json文件 [{ "id": 1, "date": "2016-05-02", "name": "张三", "address": "北京 清华大学",
}, { "id": 2, "date": "2016-05-04", "name": "李四", "address": "上海 复旦大学",
}, { "id": 3, "date": "2016-05-01", "name": "王五", "address": "广东 中山大学",
}, { "id": 4, "date": "2016-05-03", "name": "赵六", "address": "广东 深圳大学",
}, { "id": 5, "date": "2016-05-05", "name": "韩梅梅", "address": "四川 四川大学",
}, { "id": 6, "date": "2016-05-11", "name": "刘小律", "address": "湖南 中南大学",
}, { "id": 7, "date": "2016-04-13", "name": "曾坦", "address": "江苏 南京大学",
}] 

然后我们是用以下命令将服务启动

node server.js

测试接口是否良好

打开浏览器,输入http://127.0.0.1:3000/getJson。看一看页面上是否将json文件中的json数据显示出来,如果能够显示出来,则说明这个提供json数据的服务,我们已经搭建好了。

前端调用后端接口示例

为突出重点,排除干扰,方便理解。我们的前端就写一个组件,组件有两部分:首先是一个按钮,用来调用web服务的getJson接口;然后是一个内容展示区域,拿到后端返回的数据以后,将其在组件的这块区域显示出来

首先我们看组件文件

<template> <div class="test"> <button type="button" @click="getJson">从后端取json</button> <div class="showJson">{{json}}</div> </div> </template> <script> import {store} from '../vuex' export default { computed: {
          json(){ return store.state.json;
          }
        }, methods: {
          getJson(){
              store.dispatch("getJson");
          }
        }
    } </script> <style scoped> .showJson{ width:500px; margin:10px auto; min-height:500px; background-color: palegreen;
  } </style> 

非常简单,就不多解释了。
然后看我们的vuex文件

import Vue from 'vue' import Vuex from 'vuex';

Vue.use(Vuex) const state = { json: [],
}; const mutations = {
  setJson(state, db){
    state.json = db;
  }
} const actions = {
  getJson(context){ // 调用我们的后端getJson接口 fetch('http://127.0.0.1:3000/json', { method: 'GET', // mode:'cors', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json',
      },
    }).then(function (res) { if(res.status === 200){ return res.json()
      }
    }).then(function (json) { //console.log(typeof Array.from(json), Array.from(json)); context.commit('setJson', Array.from(json));
    })
  }
}; export const store = new Vuex.Store({ state: state, mutations: mutations, actions: actions,
})

ok, 代码撸完了,获取后端数据之前是这样的。

获取后端数据之后是这样的。

说说axios

想要把本demo的fetch改为axios方式,要做的工作有以下几处:
1、安装axios、在vuex文件引用axios

npm i axios import axios from 'axios'

2、将fetch部分代码替换为:

const actions = {
  getJson(context){
    axios.get('/json', { method: 'GET', // mode:'cors', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json',
      },
    }).then(function (res) { if(res.status === 200){ return res.data
      }
    }).then(function (json) { //console.log(typeof Array.from(json), Array.from(json)); context.commit('setJson', Array.from(json));
    })
  }
};

3、又会遇到跨域,在webpack中修改,路径config/index.js文件中添加proxyTable项的配置:

proxyTable: { '/json': { target: 'http://127.0.0.1:3000', changeOrigin: true, pathRewrite: { '^/json': '/json' }
      }
    },

后记

基于vue脚手架搭建的项目,模拟异步取数据,也可以直接在脚手架生成的static文件夹下放置数据,假装是后台拿过来的数据。

不过搭建一个基于express或者koa的web服务,确实也该是一个前端工程师应该掌握的。

OK,以上就是全文了。
如果这篇文章使你有所收获,不胜荣幸。
欢迎点赞,以期能帮助更多同学!

GitHub如何配置SSH Key

前端达人

文章目录

    • 步骤


    • https://github.com/xiangshuo1992/preload.git
      git@github.com:xiangshuo1992/preload.git
      这两个地址展示的是同一个项目,但是这两个地址之间有什么联系呢?
      前者是https url 直接有效网址打开,但是用户每次通过git提交的时候都要输入用户名和密码,有没有简单的一点的办法,一次配置,永久使用呢?当然,所以有了第二种地址,也就是SSH URL,那如何配置就是本文要分享的内容。
      GitHub配置SSH Key的目的是为了帮助我们在通过git提交代码是,不需要繁琐的验证过程,简化操作流程。
      
      步骤
              

      一、设置git的user name和email

      如果你是第一次使用,或者还没有配置过的话需要操作一下命令,自行替换相应字段。
      git config --global user.name "Luke.Deng"
      git config --global user.email  "xiangshuo1992@gmail.com"
            
              

      二、检查是否存在SSH Key

      cd ~/.ssh
      ls
      或者
      ll
      //看是否存在 id_rsa 和 id_rsa.pub文件,如果存在,说明已经有SSH Key
      如果没有SSH Key,则需要先生成一下
      
      
      ssh-keygen -t rsa -C "xiangshuo1992@gmail.com"
            
              

      三、获取SSH Key

      cat id_rsa.pub
      //拷贝秘钥 ssh-rsa开头
            
              

      四、GitHub添加SSH Key

      GitHub点击用户头像,选择setting
       
      新建一个SSH Key 
      取个名字,把之前拷贝的秘钥复制进去,添加就好啦。
            
              

      五、验证和修改

      测试是否成功配置SSH Key
      
      
      ssh -T git@github.com
      //运行结果出现类似如下
      Hi xiangshuo1992! You've successfully authenticated, but GitHub does not provide shell access.
      之前已经是https的链接,现在想要用SSH提交怎么办?
      直接修改项目目录下 .git文件夹下的config文件,将地址修改一下就好了。
            
              


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



深入理解vue中的slot与slot-scope

seo达人

写在前面

vue中关于插槽的文档说明很短,语言又写的很凝练,再加上其和methods,data,computed等常用选项使用频率、使用先后上的差别,这就有可能造成初次接触插槽的开发者容易产生“算了吧,回头再学,反正已经可以写基础组件了”,于是就关闭了vue说明文档。

实际上,插槽的概念很简单,下面通过分三部分来讲。这个部分也是按照vue说明文档的顺序来写的。

进入三部分之前,先让还没接触过插槽的同学对什么是插槽有一个简单的概念:插槽,也就是slot,是组件的一块HTML模板,这块模板显示不显示、以及怎样显示由父组件来决定。 实际上,一个slot最核心的两个问题这里就点出来了,是显示不显示怎样显示

由于插槽是一块模板,所以,对于任何一个组件,从模板种类的角度来分,其实都可以分为非插槽模板插槽模板两大类。
非插槽模板指的是html模板,指的是‘div、span、ul、table’这些,非插槽模板的显示与隐藏以及怎样显示由插件自身控制;插槽模板是slot,它是一个空壳子,因为它显示与隐藏以及最后用什么样的html模板显示由父组件控制。但是插槽显示的位置确由子组件自身决定,slot写在组件template的哪块,父组件传过来的模板将来就显示在哪块

单个插槽 | 默认插槽 | 匿名插槽

首先是单个插槽,单个插槽是vue的官方叫法,但是其实也可以叫它默认插槽,或者与具名插槽相对,我们可以叫它匿名插槽。因为它不用设置name属性。

单个插槽可以放置在组件的任意位置,但是就像它的名字一样,一个组件中只能有一个该类插槽。相对应的,具名插槽就可以有很多个,只要名字(name属性)不同就可以了。

下面通过一个例子来展示。

父组件:


    
  1. <template>
  2. <div class="father">
  3. <h3>这里是父组件</h3>
  4. <child>
  5. <div class="tmpl">
  6. <span>菜单1</span>
  7. <span>菜单2</span>
  8. <span>菜单3</span>
  9. <span>菜单4</span>
  10. <span>菜单5</span>
  11. <span>菜单6</span>
  12. </div>
  13. </child>
  14. </div>
  15. </template>

子组件:


    
  1. <template>
  2. <div class="child">
  3. <h3>这里是子组件</h3>
  4. <slot></slot>
  5. </div>
  6. </template>

在这个例子里,因为父组件在<child></child>里面写了html模板,那么子组件的匿名插槽这块模板就是下面这样。也就是说,子组件的匿名插槽被使用了,是被下面这块模板使用了。


    
  1. <div class="tmpl">
  2. <span>菜单1</span>
  3. <span>菜单2</span>
  4. <span>菜单3</span>
  5. <span>菜单4</span>
  6. <span>菜单5</span>
  7. <span>菜单6</span>
  8. </div>

最终的渲染结果如图所示:



    
  1. 注:所有demo都加了样式,以方便观察。其中,父组件以灰色背景填充,子组件都以浅蓝色填充。

具名插槽

匿名插槽没有name属性,所以是匿名插槽,那么,插槽加了name属性,就变成了具名插槽。具名插槽可以在一个组件中出现N次。出现在不同的位置。下面的例子,就是一个有两个具名插槽单个插槽的组件,这三个插槽被父组件用同一套css样式显示了出来,不同的是内容上略有区别。

父组件:


    
  1. <template>
  2. <div class="father">
  3. <h3>这里是父组件</h3>
  4. <child>
  5. <div class="tmpl" slot="up">
  6. <span>菜单1</span>
  7. <span>菜单2</span>
  8. <span>菜单3</span>
  9. <span>菜单4</span>
  10. <span>菜单5</span>
  11. <span>菜单6</span>
  12. </div>
  13. <div class="tmpl" slot="down">
  14. <span>菜单-1</span>
  15. <span>菜单-2</span>
  16. <span>菜单-3</span>
  17. <span>菜单-4</span>
  18. <span>菜单-5</span>
  19. <span>菜单-6</span>
  20. </div>
  21. <div class="tmpl">
  22. <span>菜单->1</span>
  23. <span>菜单->2</span>
  24. <span>菜单->3</span>
  25. <span>菜单->4</span>
  26. <span>菜单->5</span>
  27. <span>菜单->6</span>
  28. </div>
  29. </child>
  30. </div>
  31. </template>

子组件:


    
  1. <template>
  2. <div class="child">
  3. // 具名插槽
  4. <slot name="up"></slot>
  5. <h3>这里是子组件</h3>
  6. // 具名插槽
  7. <slot name="down"></slot>
  8. // 匿名插槽
  9. <slot></slot>
  10. </div>
  11. </template>

显示结果如图:


可以看到,父组件通过html模板上的slot属性关联具名插槽。没有slot属性的html模板默认关联匿名插槽。

作用域插槽 | 带数据的插槽

最后,就是我们的作用域插槽。这个稍微难理解一点。官方叫它作用域插槽,实际上,对比前面两种插槽,我们可以叫它带数据的插槽。什么意思呢,就是前面两种,都是在组件的template里面写


    
  1. 匿名插槽
  2. <slot></slot>
  3. 具名插槽
  4. <slot name="up"></slot>

但是作用域插槽要求,在slot上面绑定数据。也就是你得写成大概下面这个样子。


    
  1. <slot name="up" :data="data"></slot>
  2. export default {
  3. data: function(){
  4. return {
  5. data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
  6. }
  7. },
  8. }

我们前面说了,插槽最后显示不显示是看父组件有没有在child下面写模板,像下面那样。


    
  1. <child>
  2. html模板
  3. </child>

写了,插槽就总得在浏览器上显示点东西,东西就是html该有的模样,没写,插槽就是空壳子,啥都没有。
OK,我们说有html模板的情况,就是父组件会往子组件插模板的情况,那到底插一套什么样的样式呢,这由父组件的html+css共同决定,但是这套样式里面的内容呢?

正因为作用域插槽绑定了一套数据,父组件可以拿来用。于是,情况就变成了这样:样式父组件说了算,但内容可以显示子组件插槽绑定的。

我们再来对比,作用域插槽和单个插槽和具名插槽的区别,因为单个插槽和具名插槽不绑定数据,所以父组件是提供的模板要既包括样式由包括内容的,上面的例子中,你看到的文字,“菜单1”,“菜单2”都是父组件自己提供的内容;而作用域插槽,父组件只需要提供一套样式(在确实用作用域插槽绑定的数据的前提下)。

下面的例子,你就能看到,父组件提供了三种样式(分别是flex、ul、直接显示),都没有提供数据,数据使用的都是子组件插槽自己绑定的那个人名数组。

父组件:


    
  1. <template>
  2. <div class="father">
  3. <h3>这里是父组件</h3>
  4. <!--第一次使用:用flex展示数据-->
  5. <child>
  6. <template slot-scope="user">
  7. <div class="tmpl">
  8. <span v-for="item in user.data">{{item}}</span>
  9. </div>
  10. </template>
  11. </child>
  12. <!--第二次使用:用列表展示数据-->
  13. <child>
  14. <template slot-scope="user">
  15. <ul>
  16. <li v-for="item in user.data">{{item}}</li>
  17. </ul>
  18. </template>
  19. </child>
  20. <!--第三次使用:直接显示数据-->
  21. <child>
  22. <template slot-scope="user">
  23. {{user.data}}
  24. </template>
  25. </child>
  26. <!--第四次使用:不使用其提供的数据, 作用域插槽退变成匿名插槽-->
  27. <child>
  28. 我就是模板
  29. </child>
  30. </div>
  31. </template>

子组件:


    
  1. <template>
  2. <div class="child">
  3. <h3>这里是子组件</h3>
  4. // 作用域插槽
  5. <slot :data="data"></slot>
  6. </div>
  7. </template>
  8. export default {
  9. data: function(){
  10. return {
  11. data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
  12. }
  13. }
  14. }

结果如图所示:

github

以上三个demo就放在GitHub了,有需要的可以去取。使用非常方便,是基于vue-cli搭建工程。

https://github.com/cunzaizhuyi/vue-slot-demo

你真的了解重排和重绘吗?

前端达人

做过前端开发的小伙伴就算不是非常理解重排与重绘,但是肯定都听过这两个词。那为什么这两个东西这么重要?因为他与我们的页面性能息息相关,今天,我们就来好好研究一下这两个东西。



浏览器的渲染流程

在讲解重排和重绘之前,我们有必要说一下浏览器的渲染流程。下面是浏览器渲染过程中最关键的几个部分。如果想了解完整的浏览器渲染流程,推荐大家去阅读李兵老师的浏览器工作原理实践,需要付费阅读。后期我也会整理一下再出一篇博客详细介绍浏览器的渲染过程。


点击查看原图


JavaScript:一般来说,我们会使用 JavaScript 来实现一些视觉变化的效果。比如用 jQuery 的 animate 函数做一个动画、对一个数据集进行排序或者往页面里添加一些 DOM 元素等。当然,除了 JavaScript,还有其他一些常用方法也可以实现视觉变化效果,比如:CSS Animations、Transitions 和 Web Animation API。
样式计算:此过程是根据匹配选择器(例如 .headline 或 .nav > .nav__item)计算出哪些元素应用哪些 CSS 规则的过程。从中知道规则之后,将应用规则并计算每个元素的最终样式。
布局:在知道对一个元素应用哪些规则之后,浏览器即可开始计算它要占据的空间大小及其在屏幕的位置。网页的布局模式意味着一个元素可能影响其他元素,例如 元素的宽度一般会影响其子元素的宽度以及树中各处的节点,因此对于浏览器来说,布局过程是经常发生的。
绘制:绘制是填充像素的过程。它涉及绘出文本、颜色、图像、边框和阴影,基本上包括元素的每个可视部分。绘制一般是在多个表面(通常称为层)上完成的。
合成:由于页面的各部分可能被绘制到多层,由此它们需要按正确顺序绘制到屏幕上,以便正确渲染页面。对于与另一元素重叠的元素来说,这点特别重要,因为一个错误可能使一个元素错误地出现在另一个元素的上层。
其中,重排和重绘影响的就是其中的布局和绘制过程。

什么是重排和重绘制
重排:当DOM的变化引发了元素几何属性的变化,比如改变元素的宽高,元素的位置,导致浏览器不得不重新计算元素的几何属性,并重新构建渲染树,这个过程称为“重排”。
重绘:完成重排后,要将重新构建的渲染树渲染到屏幕上,这个过程就是“重绘”。
简单来说,涉及元素的几何更新时,叫重排。而只涉及样式更新而不涉及几何更新时,叫重绘。对于两者来说,重排必定引起重绘,但是重绘并不一定引起重排。所以,当涉及重排时,浏览器会将上述的步骤再次执行一遍。当只涉及重绘时,浏览器会跳过Layout步骤,即:


点击查看原图


而如果既不需要重排,也不需要重绘,那么就是下面这样:


点击查看原图



浏览器会直接跳到合成阶段。显然,对于页面性能来说,不重排也不重绘 > 重绘 > 重排。

什么操作会引起重排和重绘
显然,触发重排的一般都是几何因素,这是比较好理解的:

页面第一次渲染 在页面发生首次渲染的时候,所有组件都要进行首次布局,这是开销最大的一次重排
浏览器窗口尺寸改变
元素位置和尺寸发生改变的时候
新增和删除可见元素
内容发生改变(文字数量或图片大小等等)
元素字体大小变化
还有其他一些操作也可能引发重排

查询某些属性或调用某些方法
offset(Top|Left|Width|Height)
scroll(Top|Left|Width|Height)
client(Top|Left|Width|Height)
getComputedStyle()
我们可能不太理解为什么这些操作也能引起重排,这里我先简单解释一下。因为现在的浏览器已经非常完善了,会自动帮我们做一些优化。当我们用js操作DOM的时候,浏览器并不是立马执行的,而是将操作存储在一个队列中。当达到一定数量或者经过一定时间以后浏览器再统一的去执行队列中的操作。那么回到我们刚才的问题,为什么查询这些属性也会导致重排?因为当你查询这些属性时,浏览器就会强制刷新队列,因为如果不立马执行队列中的操作,有可能得到的结果就是错误的。所以相当于你强制打断了浏览器的优化流程,引发了重排。下面我们通过一些小例子来进一步理解这段话:

首先我们来一个显然会引发重排的操作

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    #test {
      width: 100px;
      height: 100px;
      background-color: red;
      position: relative;
    }
  </style>
</head>
<body>
  <div id="test">

  </div>
  <button onclick="reflow()">click</button>
  <script>
    function reflow() {
      var div = document.querySelector("#test");
      div.style.left = '200px';
    }
  </script>
</body>
</html>



把时间轴往后拉,可以看到这几个过程,先简单介绍一些这些名词代表的含义:

Recalculate Style:这个过程就是生成CSSOM的过程
Layout:这就是布局阶段,即重排的过程
Update Layer Tree:这个阶段是更新层树的过程
Paint:该阶段是为每一层准备绘制列表的过程
Composite Layers:该阶段是利用绘制列表来生成相应图层的位图了,还涉及到合成线程和光栅化,performence面板中的Raster就是光栅化线程池 。
这里只做一个简单的介绍,对其中内容不太明白的同学可以参考李兵老师的文章或者在我的下一篇介绍浏览器渲染过程的文章中会详细解释。

那通过这个图我们可以看到,我们改变了div的left之后就触发了Layout,即重排的过程。下面我们仅改变div的背景颜色,给大家一个对比。


即不重排也不重绘
说完了重排和重绘,不要忘记我们最开始提到的,最的方式就是跳过重排和重绘阶段。你可能会想,什么情况下可以做到这一点?其实这就是我们平时说的GPU加速,具体是如何实现呢?在开发过程中,如果我们使用了某些属性,浏览器会帮助我们将使用了该属性的div提升到一个单独的合成层,而在后面的渲染中,提升到该层的div将跳过重排和重绘的操作,直接到合成阶段。在stack overflow上有问题提到了这块内容。我们翻译一下就是:
下面几个属性能让浏览器帮助我们将div提升到一个单独的合成层:

图层具有3D或透视变换CSS属性
使用加速视频解码的 video 元素
拥有 3D(WebGL) 上下文或者加速 2D 上下文的 canvas 元素
混合插件(Flash)
对自己的 opacity 做 CSS 动画或使用一个动画 webkit 变换的元素
图层使用加速的CSS过滤器
层具有作为合成层的后代
图层具有较低z索引的同级元素,该同级元素具有合成层(换句话说,该层在合成层的顶部渲染)
css will-change属性
最后一点是我加上去的,同时根据文中的内容我们可以知道,css3硬件加速是浏览器的行为,所以在不同浏览器下可能会有不同的表现形式。下面我们用一个例子来理解一下。这是李兵老师在他的专栏中提出的一个例子,我拿过来借用一下,注意box中的will-change属性:

<html>

  <head>
      <title>观察will-change</title>
      <style>
          .box {
              will-change: transform, opacity;
              display: block;
              float: left;
              width: 40px;
              height: 40px;
              margin: 15px;
              padding: 10px;
              border: 1px solid rgb(136, 136, 136);
              background: rgb(187, 177, 37);
              border-radius: 30px;
              transition: border-radius 1s ease-out;
          }

          body {
              font-family: Arial;
          }
      </style>
  </head>

  <body>
      <div id="controls">
          <button id="start">start</button>
          <button id="stop">stop</button>
      </div>
      <div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
      </div>
      <script>

          let boxes = document.querySelectorAll('.box');
          let boxes1 = document.querySelectorAll('.box1');
          let start = document.getElementById('start');
          let stop = document.getElementById('stop');
          let stop_flag = false

          start.addEventListener('click', function () {
              stop_flag = false
              requestAnimationFrame(render);
          })

          stop.addEventListener('click', function () {
              stop_flag = true
          })

          let rotate_ = 0
          let opacity_ = 0
          function render() {
              if (stop_flag)
                  return 0
              rotate_ = rotate_ + 6
              if (opacity_ > 1)
                  opacity_ = 0
              opacity_ = opacity_ + 0.01
              let command = 'rotate(' + rotate_ + 'deg)';
              for (let index = 0; index < boxes.length; index++) {
                  boxes[index].style.transform = command
                  boxes[index].style.opacity = opacity_
              }
              requestAnimationFrame(render);
          }
      </script>
  </body>

  </html>



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

【CSS基础学习】复杂选择器

前端达人

文章目录

    • CSS第二课-复杂选择器
      • 群组选择器
      • 属性选择器
      • 派生选择器
      • CSS第二课-复杂选择器

        群组选择器

        格式

        选择器1,选择器2,,,选择器n{声明的属性和属性值}

        p,h1{
            color: blue;
        }


        用于对于多个选择器进行样式修改,由简单选择器组合而成的选择器,可以是简单选择器中的任意组合,如上面代码例,就是修改了p标签和h1标签的字体颜色。

        属性选择器

        根据属性名查找元素

        格式

        元素[属性名]{
            声明的属性和属性值;
        }


        p[id]{
            color: blue;
        }


        前面添加元素的名字,然后后面加上属性名,比如上例,就是p标签,其中带有id的元素,然后把字体颜色设置为蓝色。

        根据属性值查找

        格式

        元素[属性名=属性值]{
            声明的属性和属性值;
        }


        p[class = 'p2']{
            color: blue;
        }


        和上面的根据属性名查找差不多,只不过更加了,到了属性名后面的属性值,上例就是作用于p标签,只不过条件是为带有class属性,并且属性值为p2的p标签。

        多属性选择器

        格式


        元素[属性名或属性表达式][属性名或属性表达式]..{
            声明的属性和属性值;
        }
        p[title][class]{
            color: blue;
        }



        元素后面加。属性名或属性表达式,可以加+∞个,但是没必要。上例为:设置title属性和class属性的段落p标签的样式

        根据属性值近似查找

        格式


        元素[元素名~=属性值]{
            声明的属性和属性值;
        }


        元素[属性名|=值]{
            声名的属性和属性值;
        }


        p[class~='red']{
            color: blue;
        }



        注意,这里是~=,为约等于,就是找满足符合约等于条件的标签,上例为:设置class属性的值,包含red属性名的标签

        根据标签查找

        格式


        元素名1~元素名2{
            声名的属性和属性值;
        }


        a~p{
            color: blue;
        }


        a标签后面的每一个p标签,都进行了样式的修改。

        派生选择器

        后代选择器

        格式


        父类标签 子类标签{ /*注意俩标签中间有空格*/
            声名的属性和属性值;
        }


        div strong{
            color: blue;
        }


        相邻兄弟选择器

        格式


        父标签+子标签{
            声名的属性和属性值;
        }


        #div1 + p{
            color: blue;
        }


        相邻兄弟选择器可选择紧接在另一个元素后的元素,且二者具有相同的父亲元素。注释:与子结合符一样,相邻兄弟结合符旁边可以有空白符。




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

uni-app uni.request接口封装

seo达人

uni-app uni.request接口封装

今天在做uni-app项目时,发现在uni-app中 调取后台接口需要大量的重复编辑,就在想能不能封装一个如同Vue项目中的this.$axios.get(url,data).then();格式,这样就减少了很多代码重复!!

封装为如同this.$axios.get(url,data).then();格式

第一步、

我们先在index首页中的组件部分,创建一个js文件;





第二步、

我们在uni-app的入口文件中引入request.js文件;

在入口文件中挂载到uni-app实例上;





第三步、

开始接口封装:

(以下为js文件代码)



//先把接口暴露出去

export default{

//我们先定一个uni-app方法 以便于以下操作使用uni-app调取接口时便利

request(options){

///我们使用Promise方法来实现调用接口时后面多个.then()的方法

//只有Promise能实现如同$axios后面连续多个.then()的方法

return new Promise((reslove,reject)=>{

uni.request({

...options,

success:res=>{

//判断我们在使用封装的自定义时第三个参数是否为native

//当native为true时 我们返回原数据

if(options.native){

reslove(res)

}

//当native为false时 我们直接返回data中的数据

if(res.statusCode === 200){

reslove(res.data)

}else{

//加入接口参数错误或接口地址错误时 我们返回原错误提示

reject(res)

}

}

})

})

},

//在方法中 第二个参数和第三个参数用ES6新语法来添加默认值

//接口调取get方法

get(url,data={},options={}){

//我们把传过来的参数赋给options,这样我们在使用uni-app

//this.request()方法时 传递一个参数就可以

options.url = url;

options.data = data;

options.method = 'get';

//调用上面自己定义的this.request()方法传递参数

return this.request(options)

},

//接口调取post方法

post(url,data={},options={}){

options.url = url;

options.data = data;

options.method = 'post';

return this.request(options)

}

}



这样我们就已经封装完成啦,接下来就是 在页面内使用!

第四步、

我们可以在页面中来调取已经封装好的自定义事件啦



例一:

个人建议使用ES6新语法 箭头函数 不然使用this还要重新在外面声明定义,太麻烦了,使用箭头函数就会方便很多



// 已封装好的接口方法

//本案例调取接口时 没有参数上传 直接调用的

//这样使用方法时只传递了一个参数,也就是接口地址

//第二个参数没有写,默认为空;假如有参数的话 可以直接填写

//后面的参数都为接口内已经定义好的默认值:{}空对象

//里面的res为接口返回数据中的data里面的内容

this.$H.get('/api/getIndexCarousel.jsp').then(res=>{

//res打印出来是接口返回数据中data里面的数据

console.log(res)

//赋给数据区的变量,方便本页面使用

this.swiperData = res

});



例二、



// 已封装好的接口方法

//本案例使用时 传递了三个参数

//第一个为:接口地址

//第二个为:调取接口传递的参数,方法使用时不用传参,写空对象就好

//第三个为:自定义事件中 native 的属性 若为true 则返回原数据

//若想返回原数据,必须要填写第二个参数,若没有参数,也要写空对象

//因为方法调用时 是按照传参顺序调用的,若不写 参数传递就会出错

this.$H.get('/api/getIndexCarousel.jsp',{},{

native:true

}).then(res=>{

//res打印出来的数据是接口返回来的原数据

console.log(res)

//赋给数据区的变量,方便本页面使用

this.swiperData = res

});




日历

链接

blogger

蓝蓝 http://www.lanlanwork.com

存档