环境准备
创建项目
npx create-react-app my-react
进入项目并启动
cd my-react && npm start
1
src/index.js
先把src里面的东西全部删掉,重写了index.js
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component{
render(){
return (
<div>Hellow, World</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('root'));
JSX
一个React组件中,render方法中return出去的内容就是这个组件将要渲染的内容,然后Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用。
React.createElement(
'div',
{},
'Hello, World'
)
React.createElement() 接收三个参数:
第一个参数是必填,传入的是似HTML标签名称: ul, li, div;
第二个参数是选填,表示的是属性: className;
第三个参数是选填, 子节点: 要显示的文本内容;
React.createElement() 会预先执行一些检查,以帮助你编写无错代码,但实际上它创建了一个这样的对象:
// 注意:这是简化过的结构
const element = {
type: 'div',
props: {
className: '',
children: 'Hello, world!'
}
};
元素渲染
与浏览器的 DOM 元素不同,React 元素是创建开销极小的普通对象。React DOM 会负责更新 DOM 来与 React 元素保持一致。
想要将一个 React 元素渲染到根 DOM 节点中,只需把它们一起传入 ReactDOM.render():
const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));
render方法接收两个参数,第一个参数为我们的 React 根级组件,第二个参数接收一个 DOM 节点,代表我们将把和 React 应用挂载到这个 DOM 节点下,进而渲染到浏览器中。
组件 & props
组件,从概念上类似于 JavaScript 函数。它接受任意的入参(即 “props”),并返回用于描述页面展示内容的 React 元素。
函数组件:
function Welcome(props){
renter (
<h1> Hello, {props.name} </h1>
)
}
<Welcome name="World"/>
该函数是一个有效的 React 组件,因为它接收唯一带有数据的 “props”(代表属性)对象与并返回一个 React 元素。这类组件被称为“函数组件”,因为它本质上就是 JavaScript 函数。
class组件:
class Welcome extends React.Component {
render(){
renter (
<h1> Hello, {thhis.props.name} </h1>
)
}
}
<Welcome name="World"/>
组件名称必须以大写字母开头。
组件无论是使用函数声明还是通过 class 声明,都决不能修改自身的 props。
State & 生命周期
State 与 props 类似,但是 state 是私有的,并且完全受控于当前组件。
class Clock extends React.Component {
constructor(props){
super(props)
this.state = {
date : new Date()
}
}
componentDidMount() {
//这里是Clock组件第一次被渲染到DOM时会调用,也就是挂载
}
componentWillUnmount() {
//当DOM组件Clock被删除时,会调用,也就是卸载
}
render(){
return (
<div>
<h1>Hello, World</h1>
<h2>It's {this.state.date.toLocaleTimeString()}</h2>
</div>
)
}
}
修改state中数据:
class Clock extends React.Component {
constructor(props){
super(props)
this.state = {
date: new Date()
}
}
componentDidMount() {
//这里是Clock组件第一次被渲染到DOM时会调用,也就是挂载
this.timer = setInterval(()=>{
this.tick()
},1000)
}
tick(){
this.setState({
date: new Date()
})
}
componentWillUnmount() {
//当DOM组件Clock被删除时,会调用,也就是卸载
clearInterval(this.timer)
}
render(){
return (
<div>
<h1>Hello, World</h1>
<h2>It's {this.state.date.toLocaleTimeString()}</h2>
</div>
)
}
}
不要直接修改 State,构造函数是唯一可以给 this.state 赋值的地方
this.setState({name: 'World'})
1
State 的更新可能是异步的,要解决这个问题,可以让setState接受一个函数而不是一个对象,这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数:
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
事件处理
React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。
在 React 中一个不同点是你不能通过返回 false 的方式阻止默认行为。你必须显式的使用 preventDefault 。例如,传统的 HTML 中阻止链接默认打开一个新页面,你可以这样写:
<a href="#" onclick="console.log('The link was clicked.'); return false">
Click me
</a>
在 React 中,可能是这样的:
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
class函数中绑定this
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// 此语法确保 handleClick
内的 this
已被绑定。
return (
<button onClick={() => this.handleClick()}>
Click me
</button>
);
}
}
在循环中,通常我们会为事件处理函数传递额外的参数
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
1
2
列表和key
function ListItem(props) {
return <li>{props.value}</li>;
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<ListItem key={number.toString()} value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
语法
在 JSX 中所有的属性都要更换成驼峰式命名,比如 onclick 要改成 onClick,唯一比较特殊的就是 class,因为在 JS 中 class 是保留字,我们要把 class 改成 className 。
这是一个最基本的左侧菜单栏,实现的过程很简单,官方的说明文档就有,但是我在导入layer.js之后,直接复制这段官方代码到我的编辑器上时,发现页面是这样的:
发现,绑定属性的菜单并没有下拉选项,这个问题在我导入layer.all.js之后解决了,而且发现如果是在页面的最上方导入的话也没有下拉选项,只有在html代码下面导入,才可以显示 ,不知道是什么原因。
页面截图:
tab项右键菜单:
这里右键菜单的样式并没有做太多的美化。
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的拖拽效果,首先我们需要知道事件对象几个有关于实现拖拽效果的坐标
获取事件对象 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; }注意:需要给大盒子和小盒子进行定位:子绝父相
<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。右下角小盒子移动的范围在大盒子宽度减去小盒子的宽度。
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函数。
如何在网页前端里可视化你的知识图谱
最近费尽千辛万苦构造了一份可以用(大概)的知识图谱,并且把要利用知识图谱做的领域命名实体识别和一些推荐的功能做成Web版的demo,顺带想实现一些可视化知识图谱的功能。
(凭啥知识图谱就只能在Neo4j里自嗨,不能来前端show一下,歧视吗(¬_¬))
找了做前端图表展示的开源库,D3.js和Echarts都能做,我拿Echarts实现了一下功能,先看一下在现在项目里一个基于知识图谱查询的实际效果:
接下里看看如何的实现:
<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>
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} ]
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);这样就成功实现了一个简单的图谱可视化:
————————————————
版权声明:本文为CSDN博主「游离态GLZ不可能是金融技术宅」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37477357/article/details/104857495
1.实现注册与登录功能:
要求用到验证码,登录后该出不再显示登录与注册,而是显示用户名。
2.实现预约功能:
实现“运动”与“学习”两方面的邀约功能,并将邀约数据保存到数据库中,数据库使用Mysql。
运动可以邀约:篮球、足球、乒乓球等
学习可以邀约:自习、辅导等
在正式开始编码之前,需要先导入相关jar包并配置好相关的配置文件,同时也需要导入前端给的页面代码。接着是建立好相应的数据库结构,并初步构建好三层架构的想法思路。
web层
service层
dao层
然后在这里写一下对于验证码处理和点击图片更换验证码功能的一些细节。
如下图所示,为了保证servlet层能够正确接收到界面所展示的验证码信息,同时因为session对象是项目自生成的,所以我直接获取session对象并以类似于键值对的形式将页面验证码信息存入session中。
接下来是jsp页面对于验证码展示的一些处理
在这里,因为点击验证码更换操作需要用到js,所以我百度得到了上图这样一串代码。其中时间戳的作用是通过改变每次请求的时间参数来获得刷新效果,即改变url中的响应头信息。
2.注册功能
事实上,有了登录功能的实现,注册功能的代码与其都是大同小异的。最大的不同应该就是Dao层执行的操作不同
预约功能的实现更是与注册功能的实现基本一致。所不同的应该是jsp页面对单选框输入的设置。
首先在写代码之前我们需要理清如何穿插图片呢?
可以让所有图片都float:left,用一个大盒子装进所有图片,在用一个小盒子显示图片,溢出图片就hidden,之后以每张图片的宽度来scrollLeft.
可以给每张图片一个name/id,用循环遍历所有图片
可以用float:left,但是除了我要显示的图片外,其他图片都hidden,之后每当我需要某张图片时,我就把它制定到某位置
…
在这里,我将用第二种方法,因为它很直观明了,我要哪张图片我就调哪张图片。
HTML部分:在div里面我装了一张图片,name:0, 这是为了在刚打开的时候,我们的页面是有东西的而不是一片空白。其他部分都好理解,不理解的可在下方评论。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>轮播图</title> <link rel="stylesheet" href="轮播图.css" /> <script src="轮播图.js"> </script> </head> <body> <header> <div id="oImg"> <!-- 轮流播放图片 --> <img id="insert" src="img/轮1.jpg" name="0"/> </div> <!-- 左右切换图片 --> <p id="left" οnclick="goBack()"></p> <p id="right" οnclick="goForward()"></p> <ul id="nav"> <!-- 指定某张图片 --> <li id="1" οnclick="move(this)">1</li> <li id="2" οnclick="move(this)">2</li> <li id="3" οnclick="move(this)">3</li> <li id="4" οnclick="move(this)">4</li> <li id="5" οnclick="move(this)">5</li> </ul> </header> </body> </html>
CSS:
* { margin: 0 auto; padding: 0 auto; } header { width: 100%; height: 680px; position: relative; } img { width: 100%; height: 680px; } #nav { position: absolute; bottom: 5px; left: 30%; } #nav li { width: 30px; height: 30px; line-height: 30px; text-align: center; background: #ccc; font-size: 24px; border-radius: 9px; color: darkslategrey; font-family: 'Times New Roman', Times, serif; margin: 0 25px; float: left; cursor: pointer; list-style: none; } #nav li:hover { background: peru; } #left { width: 25px; height: 24px; left: 0; top: 50%; cursor: pointer; position: absolute; background: url(img/fx1.png); } #right { width: 25px; height: 24px; right: 0; top: 50%; cursor: pointer; position: absolute; background: url(img/fx2.png); }之后我们来看重中之重JS部分
JavaScript:
// 五张图片的url var oImg1 = "img/轮1.jpg"; var oImg2 = "img/轮2.jpg"; var oImg3 = "img/轮3.jpg"; var oImg4 = "img/轮4.jpg"; var oImg5 = "img/轮5.jpg"; // 把5张图片存入一个数组 var arr = [oImg1, oImg2, oImg3, oImg4, oImg5]; window.onload = function() { //刚加载时第一张图片1号背景颜色 document.getElementById("1").style.background = "peru"; run() } //轮播 function run() { timer = setInterval(function() { //随机点数字时能接着变化 var pic = document.getElementById("insert").name; var shade = document.getElementById("insert"); //如果为最后一张图片则重新循环 if (pic == 4) { pic = -1; } //点一个数字该数字背景颜色变化其余的不变 var aLi = document.getElementsByTagName("li"); for (var j = 0; j < aLi.length; j++) { aLi[j].style.backgroundColor = "#CCCCCC"; } var i = parseInt(pic); document.getElementById("insert").src = arr[i + 1]; document.getElementById("insert").name = i + 1; //数字随图片变化 switch (i) { case 0: var temp = '2'; break; case 1: var temp = '3'; break; case 2: var temp = '4'; break; case 3: var temp = '5'; break; case -1: var temp = '1'; break; } document.getElementById(temp).style.background = "peru" }, 5000) } //右箭头 function goForward() { var temp = document.getElementById("insert").name; var oBox = document.getElementById("insert"); var aLi = document.getElementsByTagName("li"); // 数字跟着图片一起变 for (var i = 0; i < aLi.length; i++) { aLi[i].style.backgroundColor = "#CCCCCC"; } switch (temp) { case "0": var n = '2'; break; case "1": var n = '3'; break; case "2": var n = '4'; break; case "3": var n = '5'; break; case "4": var n = '1'; break; } document.getElementById(n).style.background = "peru" // 向右移动图片 for (var j = 0; j < arr.length; j++) { if (j < 4) { if (temp == j) { oBox.src = arr[j + 1]; } } else { if (temp == 4) { oBox.src = arr[0]; } } } // 轮到最后一张图片时返回第一张 if (temp < 4) { oBox.name = parseInt(temp) + 1; } else { oBox.name = 0; } } //左箭头 function goBack() { var temp = document.getElementById("insert").name; var oBox = document.getElementById("insert") var aLi = document.getElementsByTagName("li"); // 图片移动时数字也跟着变 for (var i = 0; i < aLi.length; i++) { aLi[i].style.backgroundColor = "#CCCCCC"; } switch (temp) { case "0": var n = '5'; break; case "1": var n = '1'; break; case "2": var n = '2'; break; case "3": var n = '3'; break; case "4": var n = '4'; break; } document.getElementById(n).style.background = "peru" // 向左移动图片 for (var j = 0; j < arr.length; j++) { if (j > 0) { if (temp == j) { oBox.src = arr[j - 1]; } } else { if (temp == 0) { oBox.src = arr[4]; } } } // 轮到第一张图片时返回最后一张 if (temp > 0) { oBox.name = parseInt(temp) - 1; } else { oBox.name = 4; } } //指定图片 function move(num) { var oBox = document.getElementById("insert"); var temp = document.getElementById("insert").name; var aLi = document.getElementsByTagName("li"); for (var i = 0; i < aLi.length; i++) { aLi[i].style.backgroundColor = "#CCCCCC"; } document.getElementById(num.innerHTML).style.background = "peru" switch (num.innerHTML) { case "1": oBox.src = arr[0]; oBox.name = 0; break; case "2": oBox.src = arr[1]; oBox.name = 1; break; case "3": oBox.src = arr[2]; oBox.name = 2; break; case "4": oBox.src = arr[3]; oBox.name = 3; break; case "5": oBox.src = arr[4]; oBox.name = 4; break; } }JavaScript部分我写的很详细,仔细看的话是可以看懂的,主要分3个重要部分:
用src来调用每张图片并给每张图片一个name,这样方便后面的重复使用
为下方的数字按钮匹配图片,点击1跳到第1张图片,点击2跳到第2张图片…因为我把所有的图片都存在了一个数组里,所以在匹配的时候要注意数组0位置才是数字1指定的图片
可以来回翻页,当到达最后一张图片时,我再点击下一张图片又能返回到第一张图片了,亦或者当我点击到第一张图片时,再上一张图片又回到第五张图片了
效果如下:
大家有问题可以在下方评论哦,看到了会及时回复哒!
————————————————
版权声明:本文为CSDN博主「weixin_43964414」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43964414/article/details/104844041
CSS介绍
整理完了HTML的笔记,接下来就是CSS了。我们可以使用HTML构建稳定的结构基础,而页面的风格样式控制则交给CSS来完成。网页的样式包括各种元素的颜色、大小、线形、间距等等,这对于设计或维护一个数据较多的网站来说,工作量是巨大的。好在可以使用CSS来控制这些样式,这将大大提高网页设计和维护的效率,并且使网页的整体风格很容易做到统一。
CSS概述
CSS是英文Cascading Style Sheet的缩写,中文译为层叠样式表,也有人翻译为级联样式表,简称样式表。它是一种用来定义网页外观样式的技术,在网页中引入CSS规则,可以快捷地对页面进行布局设计,可以的控制HTML标记对象的宽度、高度、位置、字体、背景等外观效果。
CSS是一种标识性语言,不仅可以有效的控制网页的样式,更重要的是实现了网页内容与样式的分离,并允许将CSS规则单独存放于一个文档中, CSS文件的扩展名为“css”。
CSS3
CSS3标准早在1995年就开始制订, 2001年提上W3C研究议程,但是,10年来CSS3可以说是基本上没有什么很大的变化,一直到2011年6月才发布了全新版本的CSS3,目前,许多浏览器都广泛支持CSS3。
CSS3是CSS技术的一个升级版本,CSS3语言将CSS划分为更小的模块,在朝着模块化的方向发展。以前的版本是一个比较庞大而且比较复杂模块,所以,把它分解成为一个个小的简单的模块,同时也加入了更多新的模块。在CSS3中有字体、颜色、布局、背景、定位、边框、多列、动画、用户界面等等多个模块。
CSS的基本用法
CSS的使用规则由两部分组成:选择器和一条或多条声明。其基本基本语法如下:
选择器{ 属性1: 值; 属性2: 值; …
属性n: 值; }
CSS的使用规则由两部分组成:选择器和一条或多条声明。其基本基本语法如下:
选择器{ 属性1: 值; 属性2: 值; …
属性n: 值; }
CSS属性
CSS的属性按照相关功能进行了分组,包含了字体、文本、背景、列表、动画等多个分组,这些属性的具体使用方法和示例将会在后续中提到。
在HTML文档中使用CSS的方法
根据CSS在HTML文档中的使用方法和作用范围不同,CSS样式表的使用方法分为三大类:行内样式、内部样式表和外部样式表,而外部样式表又可分为链入外部样式表和导入外部样式表。本节我们从四个分类来认识在HTML中使用CSS的方法。
行内样式
内部样式表
外部样式表
链入外部样式表
导入外部样式表
行内样式
行内样式(inline style),也叫内联样式,它是CSS四种使用方法中最为直接的一种,它的实现借用HTML元素的全局属性style,把CSS代码直接写入其中即可。
严格意义上行内样式是一种不严谨的使用方式,它不需要选择器,这种方式下CSS代码和HTML代码混合在一起,因此不推荐使用行内样式。行内样式的基本语法如下:
<标记 style="属性:值; 属性:值; …">
当单个文档需要特殊的样式时,应该使用内部样式表。内部样式表是将样式放在页面的head区里,这样定义的样式就应用到本页面中了,内部样式表使用style标记进行声明,是较为常用的一种使用方法。其基本语法如下:
<head> <meta charset="utf-8" /> <title></title> <style type="text/css"> 选择器1{属性:值;…} 选择器2{属性:值;…} …… 选择器n{属性:值;…} </style> </head>
<head> <meta charset="utf-8" /> <title></title> <link href="样式表路径" rel="stylesheet" type="text/css" /> </head>其中:
<head> <meta charset="utf-8" /> <title></title> <style type="text/css"> @import url("样式表路径"); </style> </head>其中:
<head> <meta charset="utf-8" /> <title></title> <style type="text/css"> @import url("样式表路径"); </style> </head>
记录仓促,遗漏之处日后补充,如有错误或不足之处,还望指正
————————————————
版权声明:本文为CSDN博主「狗狗狗狗狗乐啊」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44122062/article/details/104848745
文章目录
前言
一、白屏时间过长分析
二、针对性优化
针对animate.css
针对mint-ui的优化
针对图片的优化
三、webpack打包优化与分析
webpack-bundle-analyzer打包分析
打包优化
四、优化后线上测试速度提升
五、优化总结
前言
最近在做项目时,测试提出了在App端的H5项目入口加载时间过长,白屏等待过久,需要优化的问题,于是着手开始分析:
项目技术栈:基于Vue全家桶做的一个移动端类似WebApp的项目,使用到的第三方库有:mint-ui, echarts,momentjs。
项目痛点:白屏时间过长
一、白屏时间过长分析
通过访问线上环境,结合Chrome devtool中Network和Performance功能可以具体分析整个白屏的耗时主要在哪一块儿
Network耗时记录:
Performance性能面板
通过上面两张图分析,从浏览器发起请求到解析HTML完成这一过程中:
animate.css, mini-ui.css的请求耗时最长。
图片过大耗时。
二、针对性优化
针对animate.css
animate.css由于使用的是第三方CDN(国外服务器)所有请求时间相对较长,所以如果必须要用animate.css那么可以下载下来作为本地资源,也可以使用国内CDN,或者不用animate.css,而是针对使用到的几个CSS动画,直接自己造轮子
针对mint-ui的优化
由于mint-ui在原项目中使用的是全局引用的方式,这才导致打包资源过大,css单独请求耗时过长的问题,所以主要解决方案是按需引入mint-ui,借助 babel-plugin-component,我们可以只引入需要的组件,以达到减小项目体积的目的。
安装babel-plugin-component, 若已安装可忽略
修改 .babelrc (重点在plugins中):
{ "presets": [ ["env", { "modules": false }], "stage-2" ], "plugins": ["transform-runtime",["component", [ { "libraryName": "mint-ui", "style": true } ]]], "comments": false, "env": { "test": { "presets": ["env", "stage-2"], "plugins": [ "istanbul" ] } } }
在main.js中引用使用到的插件
import Vue from 'vue' import { Button, Cell } from 'mint-ui' import 'mint-ui/lib/style.min.css' // 引用CSS import App from './App.vue' Vue.component(Button.name, Button) Vue.component(Cell.name, Cell) /* 或写为 * Vue.use(Button) * Vue.use(Cell) */ new Vue({ el: '#app', components: { App } })
在使用的组件中改为按需引用组件
import Vue from 'vue' var Popup = Vue.component('mt-popup') var Swipe = Vue.component('mt-swipe') var SwipeItem = Vue.component('mt-swipe-item') export default { name:'my-component', components:{ Popup, Swipe, SwipeItem } }
此按需引入方案也同样适用于其他第三方UI组件库
图片小图通过webpack可以直接转为base64,而大图可以通过压缩或者换格式的方式来优化,这里推荐一个好用的图片压缩工具,工具:tinyPNG,如下是图片转换前后对比
在完成了上述优化以后,下面着重关注下webpack打包后生成的文件大小,看还有没有可以优化的余地。由于项目中已经通过路由按需加载
的方式来做了功能拆分,所以通过webpack打包后生成了很多分散的js文件,如下图:
通过上图分析可以知道打包后有几个文件相对较大,vendor.js都知道是第三方库文件打包形成,之前通过mint-ui按需加载会有一定的变化,后面记录。这里着重看另两个带hash的js文件,这里并看不出来它为什么这么大,所以这里需要用到webpack打包分析工具来做进一步的打包文件分析:webpack-bundle-analyzer
它的作用如下图,即在打包后生成打包文件大小分析图,方便我们更加直观的看到文件大小和引用情况
npm intall -D webpack-bundle-analyzer
webpack.pro.conf.js
. (这里由于只是用于生产打包分析且是通过vue-cli生成的项目框架)
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin module.exports = { // ... plugins:[ new BundleAnalyzerPlugin() ] }
运行npm run build
,(webpack默认会在打包完成时生成分析图)
版权声明:本文为CSDN博主「Sophie_U」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Sophie_U/article/details/104840167
数据类型的转化(JavaScript)—自动转化和强制转化
这一周,我来分享一下在JavaScript中的数据类型转化。
首先我们要知道在JavaScript中的数据类型有什么?在这里我就不详细介绍了,帮你总结好了。
1.布尔类型-----Boolean---isNaN()
用来判断一个变量是否为非数字的类型,是数字返回false,不是数字返回true。
2.数值类型-----Number
存储时,是按照二进制数值存储,输出时,默认都是按照十进制数值输出。
在JavaScript中二进制前加0b/0B,八进制前面加0 ,十六进制前面加0x。
如果需要按照原始进制数值输出,用格式为:
变量名称.toString(进制) ;
注意的是:S必须大写,将数值转化为字符串形式输出
如:console.log( a.toString(2) );将a转换成2进制的形式输出。
3.字符串类型-----String
JavaScript可以用单引号嵌套双引号, 或者用双引号嵌套单引号(外双内单,外单内双)
字符串是由若干字符组成的,这些字符的数量就是字符串的长度。
通过字符串的length属性可以获取整个字符串的长度。
例子:var str = 'my name is xiaoming';
console.log(str.length);
输出的结果是19。可以知道空格也代表一个字符。
4.undefined
表示没有数值-----应该有数值,但是现在没有数值
5.null
表示数值为空-----表示有数值,但是数值是“空”
上面就是数据类型的五种形式。那么它是如何转化呢?听我详细给你讲解。
在 JavaScript 程序中 , 变量中存储的数据类型没有限制,也就是在变量中可以存储任何符合JavaScript语法规范的数据类型。但是在 JavaScript 程序的执行过程中,往往需要变量中存储的数值是某种特定的数据类型,别的数据类型不行,此时就需要进行数据类型的转化。
————————————————
版权声明:本文为CSDN博主「什什么都绘」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39406353/article/details/104864224上面就是数据类型的五种形式。那么它是如何转化呢?听我详细给你讲解。
在 JavaScript 程序中 , 变量中存储的数据类型没有限制,也就是在变量中可以存储任何符合JavaScript语法规范的数据类型。但是在 JavaScript 程序的执行过程中,往往需要变量中存储的数值是某种特定的数据类型,别的数据类型不行,此时就需要进行数据类型的转化。
JavaScript中数据类型的转化,分为自动转化和强制转化:
自动转化是计算机程序,自动完成的转化。
强制转化是程序员,强行完成的转化
1.布尔类型的自动转化:
在 执行 if 判断时 ,其他数据类型会自动转化为布尔类型
其他类型转化为布尔类型的原则
0 '' undefined null NaN 这五种情况转化为false
特别提醒 0.0 0.00000 都算是0
其他的所有都会转化为 true
2.字符串的自动转化:
执行字符串拼接, +号的两侧,应该都是字符串类型,会将其他数据类型转化为字符串类型
转化原则:
//基本数据类型 / 简单数据类型------将数据数值直接转化为字符串 , 然后执行拼接操作
布尔值 true ---> 字符串 'true'
布尔值 false ---> 字符串 'fasle'
undefined ---> 字符串 'undefined'
unll ---> 字符串 'null'
数值 ---> 将数值解析转化为'对应的纯数字的字符串'
// 引用数据类型 / 复杂数据类型
数组 ---> 将 [] 中的内容,转化为字符串的形式,执行拼接操作
对象 ---> 任何对象,任何内容,都会转化为 [object Object] 固定的内容形式,执行拼接操作
函数 ---> 将所有的程序代码,转化为字符串,执行拼接操作
3.数值的自动转化:
在执行运算时,会触发数据类型的自动转化。
转化原则:
布尔类型 : true ---> 1
false ---> 0
undefined : 转化为 NaN
null : 转化为 0
字符串 :
如果整个字符串,是纯数字字符串,或者符合科学计数法 ---> 转化为对应的数值
如果字符串内有不符合数字规范的内容 ---> 转化为 NaN
数组,对象,函数:
如果是+加号执行的是字符串拼接效果,按照这些数据类型转化为字符串的原则来转化
如果是其他形式的运算 执行结果都是 NaN
4.布尔类型的强制转化:
布尔类型的强制转化就是使用JavaScript中定义好的 方法/函数 Boolean( 数据/变量 )
Boolean() 这个方法 不会改变 变量中存储的原始数值
转化原则与自动转化原则相同
0 '' undefined null NaN --------> false
其他数据,都转化为true
5.字符串类型的强制转化:
方法1,变量.toString(进制类型)
将数值强制转化为字符串,并且可以设定转化的进制,.toString() 之前,不能直接写数值,必须是写成变量的形式
进制常用的数值是 2 8 16 ,可以设定的范围是 2 - 36 进制
方法2,String( 变量 / 数据 )
将变量或者数据,转化为字符串,原则按照自动转化的原则来执行,不会改变变量中存储的原始数值
但是在字符串拼接时,会将其他数据类型自动转化为字符串
6.数字类型的强制转化:
————————————————方法1 , Number(变量/数值)
console.log( Number(true) ); // 1
console.log( Number(false) ); // 0
console.log( Number(null) ); // 0
console.log( Number(undefined) ); // NaN
console.log( Number('100') ); // 对应的数值
console.log( Number('100.123') ); // 对应的数值
console.log( Number('2e4') ); // 对应的数值
console.log( Number('123abc') ); // NaN
console.log( Number( [1,2,3,4,5] ) ); // NaN
console.log( Number( {name:'zhangsan'} ) ); // NaN
console.log( Number( function fun(){console.log('abc')} ) ); // NaN
将其他类型强制转化为数值类型,转化原则与自动转化选择相同
方法2, parseInt(变量 / 数据) 是获取变量或者数据的整数部分
从数据的 左侧起 解析获取 整数内容
console.log( parseInt(true) ); // 都是 NaN
console.log( parseInt(false) );
console.log( parseInt(null) );
console.log( parseInt(undefined) );
console.log( parseInt( {name:'zhangsan'} ) );
console.log( parseInt( function fun(){console.log('abc')} ) );
数组执行,是获取 数值部分 也就是 没有 []的部分
1,2,3,4,5 整数部分是 1 1之后是逗号 逗号不是整数,之后的部分也就不算整数
获取第一个数值的整数部分,如果有就获取,如果没有,结果是NaN
console.log( parseInt( [1,2,3,4,5] ) ); // 结果是 1
console.log( parseInt( [null,2,3,4,5] ) ); // 结果是 NaN
如果是整数就直接获取,如果是浮点数,或者科学计数法,就获取整数部分
console.log( parseInt( 100 ) ); // 整数是直接获取
console.log( parseInt( 0.0123 ) ); // 浮点数是获取整数部分
console.log( parseInt( 3.123456e3 ) ); // 科学计数法是解析之后,获取整数部分
字符串不同了
如果是纯数字的字符串
console.log( parseInt( '100' ) ); // 与数字的结果相同
console.log( parseInt( '0.0123' ) ); // 与数字的结果相同
console.log( parseInt( '3.123456e3' ) ); //3
console.log( parseInt( '3abc' ) ); //3
console.log( parseInt( '3.123' ) ); //3
方法3 , parseFloat( 变量 / 数值 )
获取浮点数部分
console.log( parseFloat(true) ); // 都是 NaN
console.log( parseFloat(false) );
console.log( parseFloat(null) );
console.log( parseFloat(undefined) );
console.log( parseFloat( {name:'zhangsan'} ) );
console.log( parseFloat( function fun(){console.log('abc')} ) );
//数值, 整数,浮点数,都会完整获取
console.log( parseFloat(100) ); //100
console.log( parseFloat(100.1234) ); //100.1234
console.log( parseFloat(1.234567e3) ); //1234.567
// 关键是字符串
// 从字符串的左侧起 解析 符合浮点数的部分
console.log( parseFloat( '100' ) ); // 与数字的结果相同
console.log( parseFloat( '0.0123' ) ); // 与数字的结果相同
console.log( parseFloat( '3.123456e3' ) ); // 科学技术法会解析
console.log( parseFloat( '3.1223abc' ) );
console.log( parseFloat( '3.123' ) );
好了,这就是在JavaScript中数据类型的转化,希望可以帮助到你。
版权声明:本文为CSDN博主「什什么都绘」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39406353/article/details/104864224
蓝蓝设计的小编 http://www.lanlanwork.com