- js
- 结束
js
资料
- 总结
- JavaScript一种直译式脚本语言,一种基于对象和事件驱动并具有安全性的客户端脚本语言;也是一种广泛应用客户端web开发的脚本语言。简单地说,JavaScript是一种运行在浏览器中的解释型的编程语言。
更多编程语言介绍:
运行机制
- 【2020-8-26】JavaScript运行机制
- JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。
- JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
- 所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。
- 所有任务分成两种
- 一种是同步任务(synchronous)
- 另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
- 异步任务指的是,不进入主线程、而进入”任务队列”(task queue)的任务,只有”任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
- 异步执行的运行机制如下:(这种运行机制又称为Event Loop(事件循环))
- 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
- 主线程之外,还存在一个”任务队列”(task queue)。只要异步任务有了运行结果,就在”任务队列”之中放置一个事件。
- 一旦”执行栈”中的所有同步任务执行完毕,系统就会读取”任务队列”,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
- 主线程不断重复上面的第三步。
- 异步执行的运行机制如下:(这种运行机制又称为Event Loop(事件循环))
- 异步任务指的是,不进入主线程、而进入”任务队列”(task queue)的任务,只有”任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
console.log(1);
setTimeout(function(){
console.log(3);
},0);
console.log(2);
//请问数字打印顺序是什么?
html引入js
js在html中的应用一般有两种方式:内联和外链;
- 内嵌:内联就是在html文件中通过在script标签里面直接写js语法
- 外链:外链是指在html文件中通过script标签的src属性引入js文件
推荐使用外链的方式,把js和html分离,方便开发和日后维护
一、在页面中嵌入js
这是在页面使用js最简单的方式了。用 <\script><\/script> 把js代码标识清楚。
最好是把script元素写在</body>前面,script元素的内容就是js代码。
像这样:
<script>
// 在这里写js
function test(){
alert('hello,world');
}
test();
</script>
二、引用外部js文件
引用外部js文件,可以使js文件和HTML文件相分离、一个js文件可被多个HTML文件使用、维护起来也更方便等等。
- 1、先写好js代码,存为后缀为.js的文件,如jquery-1.7.1min.js
- 2、在HTML文件中的 < /body > 前添加代码,src是js文件的路径
- 3、如果js文件里,有函数,在HTML文件里,用 a href=”#” onclick=”js_method();return false;” 这种方法进行触发调用
<!-- 当前目录 -->
<script src="jquery-1.7.1min.js"></script>
<!-- 子目录 js -->
<script src="js/jquery-1.7.1min.js"></script>
<!-- 上一级目录 ../js -->
<script src="../js/jquery-1.7.1min.js"></script>
<!-- 绝对路径: 远程 -->
<script src="http://../bootstrap-3.3.6-dist/jquery.min.js"></script>`
<!-- 绝对路径: 本地 -->
<script src="file://E:\soft\bootstrap-3.3.6-dist\jquery.min.js"></script>`
...
</body>
外部文件引入方式
- 相对路径
- (1).如果源文件与引用js文件同目录,直接写上js文件名,例如:
<script text="javascript" src="javascript.js"></script>
- (2).如果源文件所引用js文件是在当前目录下的子目录中。直接写上js文件所在文件夹名字跟js文件名 例如:
<script text="javascript" src="js/javascript.js"></script>
- (3).如果源文件所引用js文件是在上一级目录中。使用 ../ 返回到上一级目录在写上js文件名 例如:
<script text="javascript" src="../javascript.js"></script>
- (4).如果想引用上两级目录,可以
..\..\
.
:代表目前所在的目录,相对路径。 如:<a href="./abc">文本</a>
或<img src="./abc" />
..
:代表上一层目录,相对路径。 如:<a href="../abc">文本</a>
或<img src="../abc" />
../../
:代表的是上一层目录的上一层目录,相对路径。 如:<img src="../../abc" />
/
:代表根目录,绝对路径。 如:<a href="/abc">文本</a>
或<img src="/abc" />
D:/abc/
:代表根目录,绝对路径。
- (1).如果源文件与引用js文件同目录,直接写上js文件名,例如:
- 绝对路径: 引入磁盘文件要加
file://
- (1).
<link href="file://E:\soft\bootstrap-3.3.6-dist\css\bootstrap.min.css" rel="stylesheet">
- (2).
<script src="file://E:\soft\bootstrap-3.3.6-dist\jquery.min.js"></script>
- (1).
- link引入的是css文件 src引入js文件
- src是source缩写,指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置;在请求src资源时会将其指向的资源下载并应用到文档内,例如js脚本,img图片和frame等元素。
<script src ="js.js"></script>
- 当浏览器解析到该元素时,会暂停其他资源的下载和处理,直到将该资源加载、编译、执行完毕,图片和框架等元素也如此,类似于将所指向资源嵌入当前标签内。这也是为什么将js脚本放在底部而不是头部。
- href是Hypertext Reference的缩写,指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的链接,如果我们在文档中添加
<link href="common.css" rel="stylesheet"/>
- 那么浏览器会识别该文档为css文件,就会并行下载资源并且不会停止对当前文档的处理。这也是为什么建议使用link方式来加载css,而不是使用@import方式。
总结
HTML中嵌入JavaScript的三种方式
- οnclick=”js代码“
- script 脚本块
- script src引入外部js文件
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HTML中嵌入JavaScript的第三种方式</title>
</head>
<body>
<!-- 第一种方式: onclick -->
<!--点击按钮弹出消息框-->
<input type="button" value="Hello" onclick="window.alert('Hello JavaScript!')"/>
<input type="button" value="Hello" onclick="window.alert ('Hello MengYangChen');
alert('Hello MengYang')
alert('Hello Meng')"/>
<!-- 第二种方式: 脚本块 -->
<input type="button" value="我是一个。。"/>
<script type="text/javascript">
window.alert("hello world!");
</script>
<input type="button" value="我是一个按钮对象"/>
<!-- 第三种方式: 外部js引用 -->
<script type="text/javascript" src="file/JS1.js"></script>
</body>
</html>
问题
【2024-12-13】 html 导入 本地 js包失效
- 使用远程地址 —— 成功
- 下载到本地, 使用本地地址 —— 失败, 原因是 pdf.js 文件有内部依赖未下载
原因不明
代码
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>文档数字化平台</title>
<!-- 下载pdf js依赖文件两个: pdf.js, pdf.worker.js 到 js 目录下
https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.js
https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.worker.js -->
<!-- 本地js调用 -->
<!-- <script src="/js/pdf.js" type="text/javascript" charset="utf-8"></script> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.js" type="text/javascript" charset="utf-8"></script>
</head>
加载顺序
js加载顺序
- 计算机读代码的顺序是从上往下读的, html文件中的顺序: <\head> → <\body> → body后方
javascript代码位置
- (1) <\head> 里面:
- 网页主体(body)还未加载,所以这里适合放一些立即执行且不需要引入什么参数来进行操作的的自定义函数,立即执行的语句则很可能会出错(视浏览器而定)
- (2) <\body> 里面:
- 这里可以放函数也可以放立即执行的语句,但是如果需要和网页元素互动的(比如获取某个标签的值或者给某个标签赋值),Javascript代码务必在标签的后面
- (3) <\body> 下面:
- 整个网页已经加载完毕,所以最适合放需要立即执行的命令,而自定义函数之类的则不适合。
推荐位置
- 规范起见,推荐放到body结束标签的末尾,包含到body标签内
<body>
<div>
<span>这里是你页面的内容</span>
</div>
<!-- js内容放在</body>上面,页面内容下面 -->
<script src="js/jquery-1.12.1.min.js" type="text/javascript"></script>
<script>
function hello(){
console.log("你好");
}
</script>
</body>
这样处理的好处是
- 1、无需担心因页面未完成加载,造成DOM节点获取不到,使脚本报错的问题
- 2、而且能避免因脚本运行缓慢造成页面卡死的问题。
另外,Yahoo的前端优化指南里就有这一条。参考
基础知识
js 语法
- JS 变量数据类型
- 数据类型有7种: number、boolean、symbol、string、object、undefined、function。null 有属于自己的数据类型 Null
String
:字符串类型。用”“和’‘包裹的内容,称为字符串。Number
:数值类型。可以是小数,也可以是正数。Number可以表示十进制,八进制,十六进制整数,浮点数,科学记数法,最大整数是2^53,BigInt可以表述任意大的整数boolean
:真假,可选值true/false。Object
:(复杂数据类型)Null
:表示为空的引用。var a = null; null表示一个对象不存在,其数据类型为ObjectUndefined
:未定义,用var声明的变量,没有进行初始化赋值。var a;- 声明了但未赋值的变量,其值是 undefined ,typeof 也返回 undefined
- 任何变量均可通过设置值为 undefined 进行清空。其类型也将是 undefined
- 空值与 undefined 不是一回事,空的字符串变量既有值也有类型。
- 语句
- 语句分号( ;)结尾,大括号包裹语句块(基本与Java语法类似);严格区分大小写;没有添加分号时浏览器自动添加,但是消耗资源并且可能添加出错
- 类型判断(js数据类型判断)
- typeof(a)
- toString最完美
- instanceof
- instanceof 是用来判断 A 是否为 B 的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。 在这里需要特别注意的是:instanceof 检测的是原型
- constructor
- constructor是原型prototype的一个属性,当函数被定义时候,js引擎会为函数添加原型prototype
- 注意:①null 和 undefined 无constructor,这种方法判断不了。②如果自定义对象,开发者重写prototype之后,原有的constructor会丢失
- 元素遍历, js数组遍历
- 1.for循环: 4个元素的arr, 普通for循环最优雅
for(j=0;j<arr.length;j++)
# 循环4次js for(j=0,len=arr.length;j<len;j++)
# 循环4次,优化,算一次长度for(j=0;arr[j]!=null;j++)
# 性能弱于上面
- forin
for(a in arr)
# 循环5次,末尾是undefine
- 2.foreach 循环
- 3.map 循环
- 4.forof 遍历
for(let value of arr)
# 需要ES6支持,forin<性能<for
- 5.filter 遍历
- 6.every 遍历
- 7.some 遍历
- 8.reduce
- 9.reduceRight
- 10.find
- 11.findIndex
- 12.keys,values,entries
- 1.for循环: 4个元素的arr, 普通for循环最优雅
- 总结: JS几种数组遍历方式总结
- JavaScript基础知识整理
- 变量
- 变量是用于存储信息的”容器”,是命名的内存空间,可以使用变量名称找到该内存空间;
- JavaScript 的变量是松散类型(弱类型)的,就是用来保存任何类型的数据。在定义变量的时候不需要指定变量的数据类型。
- JavaScript 定义变量有四种方法:const、let、var,还有一种是直接赋值,比如a = “ a”(不规范,不推荐使用)
- var 定义的变量可以修改,如果不初始化会输出undefined,不会报错。
- let let是块级作用域,定义的变量只在let 命令所在的代码块内有效,变量需要先声明再使用。
- const 定义的变量不可以修改,而且必须初始化,const定义的是一个恒定的常量,声明一个只读的常量或多个,一旦声明,常量值就不能改变。
- 作用域
- 在函数外声明的变量作用域是全局的,全局变量在 JavaScript 程序的任何地方都可以访问;
- 在函数内声明的变量作用域是局部的(函数内),函数内使用 var 声明的变量只能在函数内容访问。
- 对象
- JavaScript 对象是拥有属性和方法的数据,是变量的容器。对象:是封装一个事物的属性和功能的程序结构,是内存中保存多个属性和方法的一块存储空间。JavaScript中所有事物都是对象:数字、字符串、日期、数组等。JavaScript对象可以是字面量创建、分配给变量,数组和其他对象的属性、 作为参数传递给函数、有属性和作为返回值。
- JS对象分为三类:
- 内置对象(静态对象):js本身已经写好的对象,可以直接使用不需要定义它。
- 常见的内置对象有 Global、Math(它们也是本地对象,根据定义每个内置对象都是本地对象)。
- 本地对象(非静态对象):必须实例化才能使用其方法和属性的就是本地对象。
- 常见的本地对象有 Object、Function、Data、Array、String、Boolean、Number、RegExp、Error等
- 宿主对象:js运行和存活的地方,它的生活环境就是DOM(文档对象模式)和BOM(浏览器对象模式)。
- 内置对象(静态对象):js本身已经写好的对象,可以直接使用不需要定义它。
- JavaScript函数
- 使用函数前要先定义才能调用,函数的定义分为三部分:函数名,参数列表
- 四种调用模式:
- 函数调用模式(通过函数调用)
- 方法调用模式(通过对象属性调用)
- 构造函数模式(如果是作为构造函数来调用,那么this指向new创建的新对象)
- 函数上下文(借用方法模式:它的this指向可以改变,而前三种模式是固定的);
- 函数上下文就是函数作用域;基本语法:apply 和 call 后面都是跟两个参数。)
- 在javascript函数中,函数的参数一共有两种形式:(实际参数与形式参数)
- 形参:在函数定义时所指定的参数就称之为“函数的形参”。
- 实参:在函数调用时所指定的参数就称之为“函数的实参”。
- this
- 方法中的this指向调用它所在方法的对象。单独使用this,指向全局对象。函数中,函数所属者默认绑定到this上。
- 闭包
- 闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包就是创建了一个不销毁的作用域。闭包需要了解的几个概念: 作用域链、执行上下文、变量对象。
- Window
- 所有浏览器都支持 window 对象。它表示浏览器窗口。所有 JavaScript 全局对象、函数以及变量均自动成为 window 对象的成员。
- 全局变量是 window 对象的属性。全局函数是 window 对象的方法。
- 如:Document对象包含当前文档的信息,例如:标题、背景、颜色、表格等,screen,location,history等
- JSON
- JSON 是一种轻量级的数据交换格式;JSON是独立的语言 ;JSON 易于理解。
- 输出方式
document.write()
//向body中写入字符串,输出到页面,会以HTML的语法解析里面的内容cosole.log()
//向控制台输出alert()
//弹出框,会以文本的原格式输出prompt('提示文字','默认值')
// 输入框—不常用
myObj = { "name":"Nya", "age":21, "car":null };
// 访问对象JSON值,嵌套的JSON对象,使用点号和括号访问嵌套的JSON对象
x = myObj.name;
x = myObj["name"];
console.log(typeof null); //返回object
function demo(){
console.log('demo');
}
console.log(typeof demo); // 返回function
// 分支
var a = 1;
switch(a){
case 1:
console.log("1");
break;
case 2:
console.log("2");
break;
default:
console.log("其他");
break;
}
// for
function p(i){
document.write(i);
document.write("<br>");
}
for(var i = 0; i < 10; i++){
p(i);
}
// for in
for (x in myObj){
document.write(myObj[x] + "<br />")
}
//new创建对象
var person = new Person();
person.name = "Nya";
person.age = 21;
person.sex = "男";
//创建了对象的一个新实例,并向其添加了四个属性
//函数创建对象
function person(name, age, sex){
this.name = name;
this.age = age;
this.sex = sex //在JS中,this通常指向的是我们正在执行的函数本身,或者是指向该函数所属的对象(运行时)
}
//创建对象实例
var myFather = new person("Ton", 51, "男");
var myMother = new person("Sally", 49, "女");
// 返回一个包含所有的cookie的字符串,每条cookie以分号和空格(; )分隔(即key*=*value键值对):
allCookies = document.cookie;
// 设置高度、宽度
document.write("可用宽度: " + screen.availWidth + '高度:' +screen.availHeight);
//改变当前网页地址(加载新的网页):
location.href = 'http://www.baidu.com';
//返回(当前页面的)整个URL:
document.write(location.href);
// 自调用函数,匿名函数
(function () {
var x = "Hello!!"; // 我将调用自己
})();
//以上函数实际上是一个匿名自我调用的函数(没有函数名)
- html示例:
- 上一页/下一页
<script type="text/javascript">
自己编写的js代码
</script>
<!-- ① 将上面的代码放在<head></head>或者<body></body>之间 -->
<!-- ② 直接保存为js文件,然后外部调用<script type="text/javascript" src="js文件"></script> -->
<input type="button" value="Back" onclick="goBack()">
<script>
function goBack(){
window.history.back()
}
</script>
<input type="button" value="Forward" onclick="goForward()">
<script>
function goBack(){
window.history.forwardk()
}
</script>
<!-- 交互事件 -->
<h1 onclick="this.innerHTML='Ooops!'">点击文本!</h1>
<!-- 操作DOM元素,例:向button元素分配onclick事件 -->
document.getElementById("myBtn").onclick=function(){displayDate()};
<!-- 操作style样式 -->
document.getElementsByClassName('box')[0].style.background = 'red';
js 采坑
string 跨行
跨多行的字符串:
- 用模板字面量
- 用 + 运算符 - JavaScript 连接运算符
- 用 \ 运算符 – JavaScript 反斜杠运算符和转义字符
let learnCoding = `How to start learning web development?
- Learn HTML
- Learn CSS
- Learn JavaScript
Use freeCodeCamp to learn all the above and much, much more !
`
let learnCoding = 'How to start learning web development?\n' +
' - Learn HTML\n' +
' - Learn CSS\n' +
' - Learn JavaScript\n' +
' Use freeCodeCamp to learn all the above and much, much more!'
let learnCoding = 'How to start learning web development? \n \
- Learn HTML \n \
- Learn CSS\n \
- Learn JavaScript \n \
Use freeCodeCamp to learn all the above and much, much more!'
console.log(learnCoding);
string format
【2023-8-21】JavaScript: 如何使用 format 格式化字符串
- 把 js里的format当做python使用,出现隐藏问题: 字符串顺序混乱
- 实测: 方法1 管用
// format 有bug:
// 比如 '{0} {1}'.format('{1}', '{0}') 的结果是 {0} {1},和预期的 {1} {0} 不一致。
var s = '你好 {0} {1}'.format('value1', 123)
// ----- 解决1 ------
// 使用 ES6
var name = 'letian'
var s = `Hello ${name}`
console.log(s)
// ----- 解决2 ------
// String 原型中增加 format 函数
String.prototype.format = function() {
var formatted = this;
for( var arg in arguments ) {
formatted = formatted.replace("{" + arg + "}", arguments[arg]);
}
return formatted;
};
var s = '你好 {0} {1}'.formar('value1', 123)
console.log(s)
JavaScript 本地储存
- 【2021-3-23】JavaScript本地储存有localStorage、sessionStorage、cookie多种方法
- sessionStorage:仅在当前会话下有效,关闭页面或浏览器后被清除;
- setItem(key,value) 设置数据
- getItem(key) 获取数据
- removeItem(key) 移除数据
- clear() 清除所有值 2. localStorage :HTML5 标准中新加入的技术,用于长久保存整个网站的数据,保存的数据没有过期时间,直到手动去删除;
- localStorage和sessionStorage最大一般为5MB,仅在客户端(即浏览器)中保存,不参与和服务器的通信;
- 主要方法同sessionStorage 3. Cookie
- Cookie 是一些数据, 存储于你电脑上的文本文件中,用于存储 web 页面的用户信息. Cookie 数据是以键值对的形式存在的,每个键值对都有过期时间。如果不设置时间,浏览器关闭,cookie就会消失,当然用户也可以手动清除cookie. Cookie每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题, Cookie内存大小受限,一般每个域名下是4K左右,每个域名大概能存储50个键值对
- 通过访问document.cookie可以对cookie进行创建,修改与获取。默认情况下,cookie 在浏览器关闭时删除,你还可以为 cookie的某个键值对 添加一个过期时间. 如果设置新的cookie时,某个key已经存在,则会更新这个key对应的值,否则他们会同时存在cookie中
- 总结
- 相同点:都保存在浏览器端
- 不同点
- ① 传递方式不同
- cookie数据始终在同源http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。
- sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
- ② 数据大小不同
- cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下。
- 存储大小限制也不同,cookie数据不能超过4k,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如会话标识。
- sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
- ③ 数据有效期不同
- sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;
- localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;
- cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
- ④ 作用域不同
- sessionStorage不在不同浏览器窗口中共享,即使是同一个页面;
- localStorage 在所有同源窗口中都是共享的;
- cookie也是在所有同源窗口中都是共享的。
- Web Storage 支持事件通知机制,可以将数据更新的通知发送给监听者。Web Storage 的 api 接口使用更方便。
- ① 传递方式不同
- 代码
// ============sessionStorage============
// 添加数据
window.sessionStorage.setItem("name","李四")
window.sessionStorage.setItem("age",18)
// 获取数据
console.log(window.sessionStorage.getItem("name")) // 李四
// 清除某个数据
window.sessionStorage.removeItem("gender")
// 清空所有数据
window.sessionStorage.clear()
// ============localStorage============
// 添加数据
window.localStorage.setItem("name","张三")
window.localStorage.setItem("age",20)
window.localStorage.setItem("gender","男")
// 获取数据
console.log(window.localStorage.getItem("name")) // 张三
// 清除某个数据
window.localStorage.removeItem("gender")
// 清空所有数据
window.localStorage.clear()
// ===========cookie==========
// 设置cookie
document.cookie = "username=orochiz"
document.cookie = "age=20"
// 读取cookie
var msg = document.cookie
console.log(msg) // username=orochiz; age=20
// 添加过期时间(单位:天)
var d = new Date() // 当前时间 2019-9-25
var days = 3 // 3天
d.setDate(d.getDate() + days)
document.cookie = "username=orochiz;"+"expires="+d
// 删除cookie (给某个键值对设置过期的时间)
d.setDate(d.getDate() - 1)
console.log(document.cookie)
异步请求Ajax
- 请求:
- 同步请求:只有当一次请求完全结束以后才能够发起另一次请求
- 异步请求:不需要其他请求结束就可以向服务器发起请求
- 向服务器发起请求的时候,服务器不会像浏览器响应整个页面,而是只有局部刷新。它是一个异步请求,浏览器页面只需要进行局部刷新,效率非常的高
ajax
代码:
$.ajax({
// 请求方式
type:"post",
// contentType
contentType:"application/json",
// dataType
dataType:"json",
// url
url:url,
// 把JS的对象或数组序列化一个json 字符串
data:JSON.stringify(data),
// result 为请求的返回结果对象
success:function (result) {
if (200 == result.code){
alert("启动成功");
}else{
alert("启动失败");
}
}
});
JavaScript 框架
前端三大框架:Angular
、React
、Vue
jQuery
: 大家熟知的JavaScript框架,优点是简化了DOM操作,缺点是DOM操作太频繁,影响前端性能;在前端眼里使用它仅仅是为了兼容IE6、7、8。- jQuery 函数是
$()
函数(jQuery 函数)。jQuery 库包含以下功能: - HTML 元素选取、元素操作、CSS 操作、HTML 事件函数、JavaScript 特效和动画、
- HTML DOM 遍历和修改、AJAX、Utilities
- 面向对象编程包括 创建对象、原型继承、class继承。
- 类是对象的类型模板;实例是根据类创建的对象。
- jQuery 函数是
- (1)
Angular
: Google 收购的前端框架,由一群Java程序员开发,其特点是将后台的MVC模式搬到了前端并增加了模块化开发的理念,与微软合作,采用TypeScript语法开发;对后台程序员友好,对前端程序员不太友好;最大的缺点是版本迭代不合理(如: 1代-> 2代,除了名字,基本就是两个东西;截止发表博客时已推出了Angular6)。- 其最为核心的特性为:MVC、模块化、自动化双向数据绑定、语义化标签及依赖注入等。
- (2)
React
: Facebook 出品,一款高性能JS前端框架; 特点是提出了新概念虚拟DOM
用于减少真实DOM操作,在内存中模拟DOM操作,有效的提升了前端渲染效率;缺点是使用复杂,因为需要额外学习一门[JSX] 语言。- React 被称为构建用户接口而提供的Javascript库;主要用来构建UI,其专注于MVC的V部分。
- (3)
Vue
: 渐进式JavaScript框架,所谓渐进式就是逐步实现新特性的意思,如实现模块化开发、路由、状态管理等新特性。其特点是综合了Angular
(模块化)和React
(虚拟DOM)的优点;。vue.js
是用来构建web应用接口的一个库,技术上,Vue.js
重点集中在MVVM
模式的ViewModel层,连接视图和数据绑定模型通过两种方式。- 【2021-10-28】Vue可视化拖拽编辑工具附源码,拖拽生成vue代码
Axios
:前端通信框架;因为Vue 边界很明确,就是为了处理DOM,所以并不具备通信能力,此时就需要额外使用一个通信框架与服务器交互;当然也可以直接选择使用jQuery提供的AJAX通信功能。D3.js
- 数据可视化和图表是Web应用中不可或缺的一部分。
- d3.js 是最流行的可视化库之一,允许绑定任意数据到DOM,然后将数据驱动转换应用到Document中。
UI框架
- Ant-Design:阿里巴巴出品,基于React的UI框架
- ElementUI、 iview、 ice: 基于Vue的UI框架
- Bootstrap:Twitter推出的一个用于前端开发
- AmazeUI:又叫”妹子UI”,一款HTML5跨屏前端框架
JavaScript 构建工具
node.js
node.js、npm、vue、webpack 之间的关系
- node.js 是javascript运行环境,以前只能浏览器解析js,现在直接用chrome的v8引擎封装成
nodejs
,实现js独立于浏览器也可以解析运行 - npm,前端依赖包管理器(包含在nodejs中),类似 maven,帮助下载和管理前端的包,这个下载源是外国服务器,如果想提高下载速度的话,建议更换成淘宝镜像,类似maven之于阿里云镜像。
- vue.js 前端框架,其他大火的前端框架:anjularjs
- WebPack webpack 能够把 .vue 后缀名的文件打包成浏览器能够识别的js,而这个 .vue 文件装换需要打包器
vue-loader
→npm下载→node包管理工具- 可以看做是模块打包机,做的事情:分析项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。
每个项目都有个 package.json
文件,包含称为依赖项
对象,这些对象包含项目中使用的所有包及其版本。
包管理器包括元数据,即有关软件的所有信息、运行软件所需的配置文件和一些软件二进制文件。
包管理器的一些功能包括:
- 诚信与信任
- 易于管理
- 包分组
- 避免依赖地狱
Node.js
默认包管理器 NPM
和 Facebook 开发的 Yarn
npm
NPM 代表 Node Package Manager,是 Node.js
默认包管理器。
它是一个在线存储库,包含数百万个用于发布 Node.js
开源项目的包,以及用于与存储库交互的命令行工具,并帮助进行包安装、版本控制和依赖项管理。
NPM 由三个主要部分组成:
- 在线仓库:npm 的官方网站允许您查找 javascript 包、查看文档以及发布和共享包。
-
CLI
(命令行界面):它是一个命令行工具,可帮助您与 npm 交互以安装、更新、删除和发布包。 - NPM 注册表:npm 注册表是一个大型数据库,其中包含可从世界各地访问的公开可用库。
更直观的解释是将 npmjs.com 存储库视为一个中心枢纽,它从卖家(npm 包作者)接收产品包,并将这些产品分发给买家(npm 包用户)。
为了促进向开发人员分发的过程,npmjs.com 中心雇用了勤奋的员工 (npm CLI),他们充当 npmjs.com 客户的私人助理
yarn
纱线(Yarn) 是由 Facebook 发起的包管理器,旨在解决 NPM 的缺点,并提供更高级的包管理工具来促进整体开发工作流程。
Yet Another Resource Negotiator 或 Yarn 是 Facebook 于 2016 年 10 月发起的包管理器,现在得到了 Google、Exponent 和 Tilde 等公司的支持。它的创建是为了解决 npm 的缺点,并提供更高级的包管理工具,以促进整体开发工作流程。
开发者选择 npm 而不是 yarn 的主要原因是易用性、稳定性和可用性。
Yarn 特点:
- 离线模式或零安装功能:如果软件包已经安装,Yarn 会在内部缓存中提供它,以便可以在没有互联网连接的情况下安装它。此内置缓存功能可加快安装过程。
- 改进的网络性能和弹性:Yarn 将所有请求排队,以防止请求级联并最大限度地提高网络利用率。
- 兼容性:Yarn 与 npm 和 bower 注册表兼容。
- 确定性安装算法:Yarn 使用锁定文件来确保 node_modules 目录在所有开发环境中具有完全相同的结构。
- 安全性和稳定性:每次安装后都会检查软件包的完整性,以防止软件包损坏。
原文9
Yarn 和 NPM 之间的主要区别: 如何处理包管理以及性能和安全性方法。
- Yarn 主要优势在于“即插即用”和“零安装”等高级功能,可增强性能并增强安全性。
- Yarn 还擅长在包装管理过程中提供更清洁的输出和更少的噪音。
- 与 NPM 不同,Yarn 并行安装软件包,大大加快了该过程。虽然两个包管理器共享相似的命令和易用性,但 Yarn 使用校验和验证包,确保其完整性。
- 此外,Yarn 以简洁有序的树格式呈现其输出日志,这与 NPM 更杂乱的命令堆栈形成鲜明对比。
yarn 以 npm 包的形式提供。因此,在终端中运行以下命令安装:
npm install -g yarn
bootstrap
vue
【2021-7-21】
vue 介绍
Vue
(读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。
Vue 核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。
另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
Vue CLI
Vue CLI
是 Vue 2 最棒的前端构建工具,Vue CLI
基于 Webpack
之上,是 Webpack 的超集。
- Vue CLI 基于 Webpack 构建,配置好了打包规则
- 内置热模块重载的开发服务器
- 有丰富的官方插件合集,站在 webpack 庞大的社区资源上
- 友好的图形化创建和管理 Vue 项目界面
Vue cli 在服务启动之前,把所有代码打包成 Bundle
再启动服务。这就是为什么启动一些大型项目时,特别慢的原因。
这一点上 Vite
做了大幅改善。
Vite
Vite 是 Vue
团队开发的新一代前端开发与构建工具
webpack、Rollup 和 Parcel 等js开发工具极大地改善了前端开发者的开发体验。
Vite
利用生态系统中的新进展解决 JavaScript 开发工具性能瓶颈问题
Vite
通过在一开始将应用中的模块区分为 依赖
和 源码
两类,改进了开发服务器启动时间。
依赖
大多为在开发时不会变动的纯 JavaScript。一些较大的依赖(例如有上百个模块的组件库)处理的代价也很高。依赖也通常会存在多种模块化格式(例如 ESM 或者 CommonJS)。- Vite 将会使用 esbuild 预构建依赖。esbuild 使用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快 10-100 倍。
源码
通常包含一些并非直接是 JavaScript 的文件,需要转换(例如 JSX,CSS 或者 Vue/Svelte 组件),时常会被编辑。同时,并不是所有的源码都需要同时被加载(例如基于路由拆分的代码模块)。- Vite 以 原生 ESM 方式提供源码。这实际上是让浏览器接管了打包程序的部分工作:Vite 只需要在浏览器请求源码时进行转换并按需提供源码。根据情景动态导入代码,即只在当前屏幕上实际使用时才会被处理。
使用
(1) 创建 vite 项目:
- 输入 项目名 vite_wqw
npx create-vite
// Need to install the following packages:
// create-vite@6.0.1
// Ok to proceed? (y)
// √ Project name: ... vite_wqw
// √ Select a framework: » Vanilla
// √ Select a variant: » TypeScript
// Scaffolding project in E:\ocr\vite_wqw...
// Done. Now run:
// cd vite_wqw
// npm install
// npm run dev
// 另一种命令
yarn create @vite_wqw
当前目录下创建 vite_wqw, 内容如下
.gitignore
index.html # 首页文件, title: Vite+TS, 加载主脚本 src/main.ts
package.json # vite 配置: 项目名、编译脚本、软件包依赖
tsconfig.json # ts(typescript) 配置文件, 内部默认指定源码文件 src/
/public # 静态资源目录, 默认只有 vite.svg
/src # 源码主目录
# 包含文件: main.ts ( 调用了counter.ts) , counter.ts, vite-env.d.ts, style.css, typescript.svg
(2) 安装依赖
npm install # 安装依赖
# 生成以下文件
package-lock.json
node_modules/ # 依赖包路径
# 另一种
yarn # 安装依赖
yarn dev # 启动开发环境
(3) 启动服务
npm run dev // 启动服务
npx http-server // 或启动静态服务
(4) 浏览器访问
- 地址 http://localhost:5173
目录
目录约定
├── dist/ // 默认的 build 输出目录
└── src/ // 源码目录
├── assets/ // 静态资源目录
├── config
├── config.js // 项目内部业务相关基础配置
├── components/ // 公共组件目录
├── service/ // 业务请求管理
├── store/ // 共享 store 管理目录
├── until/ // 工具函数目录
├── pages/ // 页面目录
├── router/ // 路由配置目录
├── .main.tsx // Vite 依赖主入口
├── .env // 环境变量配置
├── vite.config.ts // vite 配置选型,具体可以查看官网 api
└── package.json
【2024-12-13】 vite 实战项目 ocr_project/ocr-ui 目录
目录结构
dist/ # 发布目录
public/ # 【2024-12-13】新增公共资源目录, 要缓存、下载的静态文件放这里目录, 可以按照URL方式访问
src/ # 源码目录
配置路由
改造 main.tsx
import React from 'react'
import ReactDOM from 'react-dom'
import { HashRouter, Route, Switch } from 'react-router-dom'
import routerConfig from './router/index'
import './base.less'
ReactDOM.render(
<React.StrictMode>
<HashRouter>
<Switch>
{
routerConfig.routes.map((route) => {
return (
<Route key={route.path} {...route} />
)
})
}
</Switch>
</HashRouter>
</React.StrictMode>,
document.getElementById('root')
)
router/index.ts 文件配置
import BlogsList from '@/pages/blogs/index'
import BlogsDetail from '@/pages/blogs/detail'
export default {
routes: [
{ exact: true, path: '/', component: BlogsList },
{ exact: true, path: '/blogs/detail/:article_id', component: BlogsDetail },
],
}
可以参考上述的配置,把其他的属性也配置进去,比如重定向(redirect)、懒加载等常见路由配置项
另外个人比较倾向通过配置来生成路由,约定式路由总感觉不太方便。
service 管理
所有项目请求都放入 service,建议每个模块都有对应的文件管理,如下所示
import * as information from './information'
import * as base from './base'
export {
information,
base
}
这样可以方便请求管理
base.ts 作为业务请求类,可以在这里处理一些业务特殊处理
import { request } from '../until/request'
const prefix = '/api'
export const getAllInfoGzip = () => {
return request({
url: `${prefix}/apis/random`,
method: 'GET'
})
}
until/request 作为统一引入的请求方法,可以自定义替换成 fetch、axios 等请求库,同时可以在此方法内封装通用拦截逻辑。
import qs from 'qs'
import axios from "axios";
interface IRequest {
url: string
params?: SVGForeignObjectElement
query?: object
header?: object
method?: "POST" | "OPTIONS" | "GET" | "HEAD" | "PUT" | "DELETE" | undefined
}
interface IResponse {
count: number
errorMsg: string
classify: string
data: any
detail?: any
img?: object
}
export const request = ({ url, params, query, header, method = 'POST' }: IRequest): Promise<IResponse> => {
return new Promise((resolve, reject) => {
axios(query ? `${url}/?${qs.stringify(query)}` : url, {
data: params,
headers: header,
method: method,
})
.then(res => {
resolve(res.data)
})
.catch(error => {
reject(error)
})
})
}
具体通用拦截,请参考 axios 配置,或者自己改写即可,需要符合自身的业务需求。
这里使用 axios 构建出来的资源有问题,不要直接复制代码使用,请参考之前的请求封装替换成 fetch,如果有同学复制代码构建成功的,请留言 = =!
在具体业务开发使用的时候可以按照模块名引入,容易查找对应的接口模块
import { information } from "@/service/index";
const { data } = await information.getAllInfoGzip({ id });
“ 这套规则同样可以适用于 store、router、utils 等可以拆开模块的地方,有利于项目维护。”
上述是针对项目做了一些业务开发上的配置与约定,各位同学可以根据自己团队中的规定与喜好行修改。
其他配置
这里主要是关于 vite.config.ts 的配置,对项目整体做一些附加配置。
import { defineConfig } from 'vite'
import reactRefresh from '@vitejs/plugin-react-refresh'
import vitePluginImp from 'vite-plugin-imp'
export default defineConfig({
plugins: [
reactRefresh(),
vitePluginImp({
libList: [
{
libName: 'antd-mobile',
style(name) {
return `antd-mobile/lib/${name}/style/index.css`
},
},
]
})
],
resolve: {
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'],
alias: {
'@': '/src'
}
},
server: {
proxy: {
// 选项写法
'/api': {
target: 'https://www.xxx.xxx',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
},
}
},
css: {
postcss: {
plugins: [
require('postcss-pxtorem')({ // 把px单位换算成rem单位
rootValue: 32, // 换算基数,默认100,这样的话把根标签的字体规定为1rem为50px,这样就可以从设计稿上量出多少个px直接在代码中写多上px了。
propList: ['*'], //属性的选择器,*表示通用
unitPrecision: 5, // 允许REM单位增长到的十进制数字,小数点后保留的位数。
exclude: /(node_module)/, // 默认false,可以(reg)利用正则表达式排除某些文件夹的方法
})
]
}
}
})
大体也是一些基本内容:
- vitePluginImp 是将 antd-mobile 进行按需加载
- postcss-pxtorem 是配置移动端 px 转换的插件
- server.proxy 配置项目代理
- resolve.alias 配置别名,如果需要 vscode 正常识别的话,需要 ts.config 也配置一下
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": [
"src/*"
]
},
}
“ 其中 antd-mobile 可以自行替换成 antd,包括 postcss 也可以根据自己的喜好替换 ” 通过上述的简单改造,此时已经可以进行正常的小项目开发了。完结撒花!
并且已经在用此配置写了一个简单的 H5 项目,后续随着项目的迭代会逐步完善一下模板。
案例
文档预览功能
npm与yarn
Facebook、Google、Exponent 和 Tilde 联合推出了一个新的 JS 包管理工具 — Yarn
Yarn 是为了弥补 npm 的一些缺陷而出现的:
- npm 安装包(packages)的速度不够快,拉取的 packages 可能版本不同
- npm 允许在安装 packages 时执行代码,这就埋下了安全隐患
Yarn 没想要完全替代 npm,它只是一个新的 CLI 工具,拉取的 packages 依然来自 npm 仓库。仓库本身不会变,所以获取或者发布模块的时候和原来一样。
vue 安装
- 安装nodejs,命令行输入 node –v检测安装是否成功
- 安装vue-cli脚手架:npm i -g @vue/cli-init,命令行输入 vue –v检测安装是否成功
- 新建项目vue init webpack myVue
- 打开项目文件夹 myVue,npm install 下载依赖
- 运行项目 npm start
项目结构:
vue hello world
vue 代码运行方式
运行vue的三种方式:
- ① 在第三方网页里调试,如:CodeSandBox,可以再浏览器里直接调试
- ② 直接用html文件,如以下示例代码
- ③ 使用vue-cli工具 —— 新手不建议,除非已使用node.js工具
vue 示例
简易示例:
- html、js、css分离
- html中变量引用自js代码
- 注:注意去掉大括号中间的空格(jekyll语法规避)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> -->
<!-- 生产环境版本,优化了尺寸和速度 -->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2"></script> -->
</head>
<body>
<div id="app">
<p>{ { message } }</p>
<br>{ {v} }
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
v : "你好"
}
})
</script>
</body>
</html>
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统
- 数据和 DOM 已经被建立了关联,所有东西都是响应式的。浏览器控制台修改message变量,可以看到页面取值随时变化
- 开发者不再和 HTML 直接交互了。一个 Vue 应用会将其挂载到一个 DOM 元素上(即示例中的app)
vue 部署
vue 离线部署
- 安装 node.js 工具包
- 有网的机器上,安装vue环境依赖包,npm install
- 复制缓存目录
- 查看 缓存目录:
npm config get cache
, 一般是 npm-cache - 复制 npm-cache
- vue初始化,包括
node_modules
依赖包一起拷贝到内网
- 查看 缓存目录:
- U盘复制到内网电脑
- 双击运行 nodejs 安装包
- 安装依赖
npm install --cache ./npm-cache --optional --cache-min 99999999999 --shrinkwrap false jquery
- 运行项目: npm run dev
详见内网/离线搭建前端vue环境,没网络安装vue-cli运行项目
vue 目录结构
Vue项目结构:
顶级目录:
目录/文件 | 说明 |
---|---|
build | 项目构建(webpack)相关代码 |
config | 配置目录,包括端口号等。我们初学可以使用默认的。 |
node_modules | npm 加载的项目依赖模块 |
src | 这里是我们要开发的目录,基本上要做的事情都在这个目录里。里面包含了几个目录及文件: - assets: 放置一些图片,如logo等。 - components: 目录里面放了一个组件文件,可以不用。 - App.vue: 项目入口文件,我们也可以直接将组件写这里,而不使用 components 目录。 - main.js: 项目的核心文件。 |
static | 静态资源目录,如图片、字体等。 |
test | 初始测试目录,可删除 |
.xxxx文件 | 这些是一些配置文件,包括语法配置,git配置等。 |
index.html | 首页入口文件,你可以添加一些 meta 信息或统计代码啥的。 |
package.json | 项目配置文件。 |
README.md | 项目的说明文档,markdown 格式 |
APP.vue 文件 是项目核心
src下文件:
-src
-assets # 静态资源
-css
-js
-components # 公共组件
index.js # 整合公共组件
-filters # 过滤器
index.js # 整合过滤器
-pages # 路由组件
-home # 某个路由组件
home.vue # 路由组件
-components # 路由组件的子组件
banner.vue
list.vue
-router # 路由
index.js
-store # 仓库
index.js # 创建仓库并导出
mutations.js # 根级别下 的state mutations getters
acions.js # 根级别下的actions
-modules # 模块
-utils # 工具类
alert.js # 弹框
request.js # 数据交互
App.vue # 根组件
main.js # 入口文件
MVVM模式
MVVM模式(Model-View-ViewModel)在Vue.js中ViewModel是如何和View以及Model进行交互的
ViewModel是Vue.js的核心,它是一个Vue实例。Vue实例是作用于某一个HTML元素上的,这个元素可以是HTML的body元素,也可以是指定了id的某个元素。 当创建了ViewModel后,双向绑定是如何达成的呢?
- 首先,我们将上图中的DOM Listeners和Data Bindings看作两个工具,它们是实现双向绑定的关键。
- 从View侧看,ViewModel中的DOM Listeners工具会帮我们监测页面上DOM元素的变化,如果有变化,则更改Model中的数据;
- 从Model侧看,当我们更新Model中的数据时,Data Bindings工具会帮我们更新页面中的DOM元素。
【2022-3-10】图解vue的MVVM架构
Vue是MVVM架构,响应式,轻量级框架。
主要特点:
- 1、轻量级
- 2、双向数据绑定
- 3、指令
- 4、组件化
- 5、客户端路由
- 6、状态管理
MVVM架构是指:
- 数据层(Model):应用数据以及逻辑。
- 视图层(View):页面UI组件。
- 视图数据模型(ViewModel):数据与视图关联起来,数据和 DOM 已经建立了关联,是响应式的,使编程人员脱离复杂的界面操作
- ViewModel主要功能是实现数据双向绑定:
- 1.数据变化后更新视图
- 2.视图变化后更新数据
与jQuery比较会更清晰:
- jQuery想要修改界面中某个标签,需要以下几步:
- 搜索web页面DOM树
- 根据选择器选择到DOM
- 将数据更新到节点
vue 实例
每个 Vue 应用都是通过用 Vue 函数创建一个新的 Vue 实例开始;虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发。因此经常用 vm (ViewModel 的缩写) 这个变量名表示 Vue 实例
- 一个Vue 应用由 一个通过 new Vue 创建的根 Vue 实例,以及可选的嵌套的、可复用的组件树组成
- 所有的 Vue 组件都是 Vue 实例,并且接受相同的选项对象 (一些根实例特有的选项除外)。
根实例
└─ TodoList
├─ TodoItem
│ ├─ TodoButtonDelete
│ └─ TodoButtonEdit
└─ TodoListFooter
├─ TodosButtonClear
└─ TodoListStatistics
Vue 实例被创建时,它将 data 对象中的所有的 property 加入到 Vue 的响应式系统中。当这些 property 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。
- 数据改变时,视图会进行重渲染。
- 注意:
- 只有当实例被创建时就已经存在于 data 中的 property 才是响应式的。
- 关闭响应功能:Object.freeze(obj)
// 我们的数据对象
var data = { a: 1 }
// Object.freeze(obj) // 关闭响应
// 该对象被加入到一个 Vue 实例中
var vm = new Vue({
data: data
})
// 获得这个实例上的 property, 返回源数据中对应的字段
vm.a == data.a // => true
// 设置 property 也会影响到原始数据
vm.a = 2
data.a // => 2
// ……反之亦然
data.a = 3
vm.a // => 3
vm.b = 'hi' // 不管用,非创建时定义
// ------ vue自带函数,带$符号 ------
vm.$data === data // => true
vm.$el === document.getElementById('example') // => true
// $watch 是一个实例方法
vm.$watch('a', function (newValue, oldValue) {
// 这个回调将在 `vm.a` 改变后调用
})
实例生命周期
实例生命周期钩子
每个 Vue 实例在被创建时都要经过一系列的初始化过程
- 需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。
- 同时会运行一些生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
created 钩子用来在实例被创建之后执行代码:
new Vue({
data: {
a: 1
},
created: function () {
// `this` 指向 vm 实例
console.log('a is: ' + this.a)
}
})
// => "a is: 1"
其他钩子:如 mounted、updated 和 destroyed。生命周期钩子的 this 上下文指向调用它的 Vue 实例。
vue语法
【2022-3-15】vue.js教程
vue经典代码结构
【2022-3-1】vue教程
打开页面 http://localhost:8080/,一般修改后会自动刷新,显示效果如下所示
<!-- 展示模板 -->
<template>
<div id="app">
<img src="./assets/logo.png">
<hello></hello>
</div>
</template>
<script>
// 导入组件
import Hello from './components/Hello'
export default {
name: 'app',
components: {
Hello
}
}
</script>
<!-- 样式代码 -->
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
Vue.js的指令是以v-开头的,它们作用于HTML元素,指令提供了一些特殊的特性,将指令绑定在元素上时,指令会为绑定的目标元素添加一些特殊的行为,我们可以将指令看作特殊的HTML特性(attribute)。
Vue.js提供了一些常用的内置指令,接下来我们将介绍以下几个内置指令:
- v-if 指令:条件渲染指令,它根据表达式的真假来删除和插入元素
- v-show 指令:也是条件渲染指令,和v-if指令不同的是,使用v-show指令的元素始终会被渲染到HTML,它只是简单地为元素设置CSS的style属性。
- v-else 指令:为v-if或v-show添加一个“else块”。v-else元素必须立即跟在v-if或v-show元素的后面——否则它不能被识别。
- v-for 指令:基于一个数组渲染一个列表,它和JavaScript的遍历语法相似
- v-bind 指令:v-bind指令可以在其名称后面带一个参数,中间放一个冒号隔开,这个参数通常是HTML元素的特性(attribute),如 v-bind:class
- v-on 指令:用于给监听DOM事件,它的用语法和v-bind是类似的,例如监听< a >元素的点击事件,如 < a v-on:click=”doSomething”>
- 两种形式调用方法:绑定一个方法(让事件指向方法的引用),或者使用内联语句。
vue模板语法
几种语法:
- 文本:数据绑定最常见的形式,用“Mustache”语法 (双大括号) 的文本插值
- v-once 指令只执行一次插值
- 原始html:用 v-html 指令输出真正的 HTML
- 注意:动态渲染的任意 HTML 可能会非常危险,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值。
- Attribute:v-bind命令渲染属性
- JavaScript 表达式:Vue.js提供了完全的 JavaScript 表达式支持
- 表达式会在所属 Vue 实例的数据作用域下作为 JavaScript 被解析。
- 限制:每个绑定都只能包含单个表达式,所以下面的例子都不会生效。
- 模板表达式都被放在沙盒中,只能访问全局变量的一个白名单,如 Math 和 Date 。你不应该在模板表达式中试图访问用户定义的全局变量。
<!-- 文本 -->
<span>Message: { { msg } }</span>
<span v-once>这个将不会改变: { { msg } }</span>
<!-- 原始html -->
<p>Using mustaches: { { rawHtml } }</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
<!-- 属性 -->
<div v-bind:id="dynamicId"></div>
<!-- bool型属性控制组件是否展示 -->
<button v-bind:disabled="isButtonDisabled">Button</button>
<!-- js表达式 -->
{ { number + 1 } }
{ { ok ? 'YES' : 'NO' } }
{ { message.split('').reverse().join('') } }
<div v-bind:id="'list-' + id"></div>
<!-- 这是语句,不是表达式 -->
{ { var a = 1 } }
<!-- 流控制也不会生效,请使用三元表达式 -->
{ { if (ok) { return message } } }
绑定元素:DOM文本
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统
- 数据和 DOM 已经被建立了关联,所有东西都是响应式的。浏览器控制台修改message变量,可以看到页面取值随时变化
- 开发者不再和 HTML 直接交互了。一个 Vue 应用会将其挂载到一个 DOM 元素上(即示例中的app)
<div id="app">
<p>{ { message } }</p>
<br>{ {v} }
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
v : "你好"
}
})
</script>
vue指令
指令 (Directives) 是带有 v- 前缀的特殊 attribute。
- 当然,不一定都是v-开头,可以缩写
指令 attribute 的值预期是单个 JavaScript 表达式 (v-for 是例外)。
- 指令的职责:当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。
- 一些指令能够接收一个“参数”,在指令名称之后以冒号表示。
- 动态参数:从 2.6.0 开始,用方括号括起来的 JavaScript 表达式作为一个指令的参数;约束:
- 动态参数预期会求出一个字符串,异常情况下值为 null。这个特殊的 null 值可以被显性地用于移除绑定。任何其它非字符串类型的值都将会触发一个警告。
- 动态参数表达式有一些语法约束,因为某些字符,如空格和引号,放在 HTML attribute 名里是无效的
- 修饰符 (modifier) 是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。
<!-- 完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a :[key]="url"> ... </a>
<!-- 根据表达式 seen 的值的真假来插入/移除 <p> 元素 -->
<p v-if="seen">现在你看到我了</p>
<!-- 指令参数 -->
<!-- href 是参数,告知 v-bind 指令将该元素的 href attribute 与表达式 url 的值绑定 -->
<a v-bind:href="url">...</a>
<!-- click是参数 -->
<a v-on:click="doSomething">...</a>
<!-- 动态参数
attributeName 会被作为一个 JavaScript 表达式进行动态求值,作为最终的参数来使用。
-->
<a v-bind:[attributeName]="url"> ... </a>
<!-- 修饰符
.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault() -->
<form v-on:submit.prevent="onSubmit">...</form>
v-bind:更改属性
对应替换以上代码的html、js部分即可
<div id="app-2">
<span v-bind:title="message">
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
</div>
v-bind attribute 被称为指令
- 将元素节点(app-2)的 title attribute 和 Vue 实例的 message property 保持一致
var app2 = new Vue({
el: '#app-2',
data: {
message: '页面加载于 ' + new Date().toLocaleString()
}
})
v-if 条件与循环
控制切换一个元素是否显示也相当简单:
- 控制台输入 app3.seen = false,文字消失
<div id="app-3">
<p v-if="seen">现在你看到我了</p>
<!-- 加else -->
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
</div>
<!-- if-else-if -->
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else>
Not A/B
</div>
<!-- 应用到多个元素上 -->
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
注:
- v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别
- v-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。
- v-if只能添加到一个元素上,如何应用到多个元素上?template
var app3 = new Vue({
el: '#app-3',
data: {
seen: true
}
})
不仅可以把数据绑定到 DOM 文本或 attribute,还可以绑定到 DOM 结构。此外,Vue 也提供一个强大的过渡效果系统,可以在 Vue 插入/更新/移除元素时自动应用过渡效果。
v-show(条件展示)
另一个用于根据条件展示元素的选项是 v-show 指令。用法大致一样,不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS property display。
注意
- v-show 不支持 < template > 元素,也不支持 v-else。
<h1 v-show="ok">Hello!</h1>
v-if 与 v-show:
- v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
- v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
- 相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。 一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
v-for
v-for 指令可以绑定数组的数据来渲染一个项目列表
- 在控制台里,输入 app4.todos.push({ text: ‘新项目’ }),会发现列表最后添加了一个新项目。
- 数据方法
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
<div id="app-4">
<ol>
<!-- 可以用of代替in -->
<li v-for="todo in todos">
{ { todo.text } }
</li>
</ol>
<!-- 可以访问所有父作用域的 property(如parentMessage),以及索引index -->
<ul id="app-4">
<li v-for="(item, index) in items">
{ { parentMessage } } - { { index } } - { { item.message } }
</li>
</ul>
<!-- 第二个参数 -->
<div v-for="(value, name) in object">
{ { name } }: { { value } }
</div>
<!-- 第三个参数 -->
<div v-for="(value, name, index) in object">
{ { index } }. { { name } }: { { value } }
</div>
<!-- 遍历对象属性 -->
<ul id="app-4" class="demo">
<li v-for="value in object">
{ { value } }
</li>
</ul>
<!-- 指定遍历时采用的key -->
<div v-for="item in items" v-bind:key="item.id">
<!-- 内容 -->
</div>
<!-- template分组 -->
<ul>
<template v-for="item in items">
<li>{ { item.msg } }</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
</div>
js部分
var app4 = new Vue({
el: '#app-4',
data: {
todos: [
{ text: '学习 JavaScript' },
{ text: '学习 Vue' },
{ text: '整个牛项目' }
],
parentMessage: 'Parent',
items: [
{ message: 'Foo' },
{ message: 'Bar' }
],
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
})
注:
- 不推荐同时使用 v-if 和 v-for。请查阅风格指南以获取更多信息。
- 当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级。请查阅列表渲染指南以获取详细信息。
数组过滤
<ul v-for="set in sets">
<li v-for="n in even(set)">{ { n } }</li>
</ul>
data: {
sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
},
methods: {
even: function (numbers) { // 过滤部分数据
return numbers.filter(function (number) {
return number % 2 === 0
})
}
}
v-on事件监听(处理用户输入)
用 v-on 指令添加一个事件监听器,调用在 Vue 实例中定义的方法
- reverseMessage 方法更新了应用的状态,但没有触碰 DOM —— 所有的 DOM 操作都由 Vue 来处理,代码只需要关注逻辑层面即可。
<div id="app-5">
<p>{ { message } }</p>
<button v-on:click="reverseMessage">反转消息</button>
</div>
var app5 = new Vue({
el: '#app-5',
data: {
message: 'Hello Vue.js!'
},
methods: {
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}
}
})
v-model:双向绑定
Vue 还提供了 v-model 指令,它能轻松实现表单输入和应用状态之间的双向绑定。
<div id="app-6">
<p>{ { message } }</p>
<input v-model="message">
</div>
var app6 = new Vue({
el: '#app-6',
data: {
message: 'Hello Vue!'
}
})
vue组件系统
组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树
- 大型应用中,有必要将整个应用程序划分为组件,以使开发更易管理。
<div id="app">
<app-nav></app-nav>
<app-view>
<app-sidebar></app-sidebar>
<app-content></app-content>
</app-view>
</div>
Vue 组件类似于自定义元素——它是 Web 组件规范的一部分,这是因为 Vue 的组件语法部分参考了该规范;二者关键差别:
- Web Components 规范已经完成并通过,但未被所有浏览器原生实现。目前 Safari 10.1+、Chrome 54+ 和 Firefox 63+ 原生支持 Web Components。相比之下,Vue 组件不需要任何 polyfill,并且在所有支持的浏览器 (IE9 及更高版本) 之下表现一致。必要时,Vue 组件也可以包装于原生自定义元素之内。
- Vue 组件提供了纯自定义元素所不具备的一些重要功能,最突出的是跨组件数据流、自定义事件通信以及构建工具集成。
虽然 Vue 内部没有使用自定义元素,不过在应用使用自定义元素、或以自定义元素形式发布时,依然有很好的互操作性。Vue CLI 也支持将 Vue 组件构建成为原生的自定义元素。
一个组件本质上是一个拥有预定义选项的一个 Vue 实例。在 Vue 中注册组件很简单
// 定义名为 todo-item 的新组件
Vue.component('todo-item', {
template: '<li>这是个待办项</li>'
})
var app = new Vue(...)
调用刚定义的组件 todo-item
<ol>
<!-- 创建一个 todo-item 组件的实例 -->
<todo-item></todo-item>
</ol>
这会为每个待办项渲染同样的文本,不符合预期。应该能从父作用域将数据传到子组件才对。修改一下组件的定义,使之能够接受一个 prop
Vue.component('todo-item', {
// todo-item 组件现在接受一个"prop",类似于一个自定义 attribute。
props: ['todo'], // 这个 prop 名为 todo。
template: '<li>{ { todo.text } }</li>'
})
var app7 = new Vue({
el: '#app-7',
data: {
groceryList: [
{ id: 0, text: '蔬菜' },
{ id: 1, text: '奶酪' },
{ id: 2, text: '随便其它什么人吃的东西' }
]
}
})
用 v-bind 指令将待办项传到循环输出的每个组件中
<div id="app-7">
<ol>
<!--
现在我们为每个 todo-item 提供 todo 对象; todo 对象是变量,即其内容可以是动态的。需要为每个组件提供一个“key”
-->
<todo-item
v-for="item in groceryList"
v-bind:todo="item"
v-bind:key="item.id"
></todo-item>
</ol>
</div>
计算属性和侦听器
待补充
vue路由
直接路由,不用路由库
- computed成员 –> ViewComponent()方法 –> 路由到路径字典routes
const NotFound = { template: '<p>Page not found</p>' }
const Home = { template: '<p>home page</p>' }
const About = { template: '<p>about page</p>' }
const routes = {
'/': Home,
'/about': About
}
new Vue({
el: '#app',
data: {
currentRoute: window.location.pathname
},
computed: {
ViewComponent () {
return routes[this.currentRoute] || NotFound
}
},
render (h) { return h(this.ViewComponent) }
})
第三方路由,如 Page.js 或者 Director,整合起来也一样简单
vue框架
拖拽生成页面
【2022-3-16】低代码平台 Variant Form,只用拖拖拽拽就生成vue页面代码,体验地址:vform表单设计器
vue-element-admin(个人)
- vue-element-admin,github:极简的 vue admin 管理后台。它只包含了 Element UI & axios & iconfont & permission control & lint, demo体验地址
机器人平台demo
【2022-2-22】滴滴机器人平台采用这个模板,django+vue框架,前后端分离
# ------ 前端部分 -------
# brew install yarn
# install dependency
yarn install # 安装依赖包
# npm install
# develop
yarn run dev # 运行前端环境
# npm run dev
后端:
- Django执行manage.py 提示 NameError: name ‘_mysql’ is not defined 问题
- 原因是:Mysqldb 不兼容 python3.5 以后的版本
- 解决:用pymysql代替MySQLdb,参考
- 打开项目在setting.py的init.py,或直接在当前py文件最开头添加
- import pymysql
- pymysql.install_as_MySQLdb()
# ------ 后端部分 -------
pip install -r requirements.txt
# 准备mysql环境
mysql -h 127.0.0.1 -P 3306 -u root -pwangqiwen
vim bot_service/settings.py # 修改mysql连接信息,DATABASES选项
pip install pymysql # 安装Python的mysql接口;默认连接Python2版本的MySQL,需要改成pymysql
vim bot_service/__init__.py # 添加以下内容
# import pymysql
# pymysql.install_as_MySQLdb()
# 注释ready函数,自动创建数据库、表
vim bot_service/apps/knowledge/apps.py
# 否则报错:启动本地数据库,创建as_bot
# 报错:as_bot.knowledge...表不存在,哪里有建表语句?
python manage.py makemigrations knowledge # 建库
python manage.py migrate #
python manager.py createsuperuser # 创建管理员账户,wqw,robot@123
# 启动后端服务
python manage.py runserver 127.0.0.1:8000
【2022-2-22】Django+Vue前后端分离实战
# 克隆项目
git clone https://github.com/PanJiaChen/vue-admin-template.git
# 也可以多下载个完整的模版,用到组件时,copy过来
# git clone https://github.com/PanJiaChen/vue-element-admin.git
# 进入项目目录
cd vue-admin-template
# 安装依赖, 建议不要用 cnpm 安装 会有各种诡异的bug 可以通过如下操作解决 npm 下载速度慢的问题
npm install --registry=https://registry.npm.taobao.org
# 本地开发 启动项目
npm run dev
# ps:启动的时候报错了,提示提示vue-cli-service: command not found
# 进入到项目目录下,执行:rm –rf node_modules and npm install
Layui
layui(谐音:类 UI) 是一套开源的 Web UI 解决方案,采用自身经典的模块化规范,并遵循原生 HTML/CSS/JS 的开发方式,极易上手,拿来即用。其风格简约轻盈,而组件优雅丰盈,从源代码到使用方法的每一处细节都经过精心雕琢,非常适合网页界面的快速开发。layui 区别于那些基于 MVVM 底层的前端框架,却并非逆道而行,而是信奉返璞归真之道。准确地说,它更多是面向后端开发者,你无需涉足前端各种工具,只需面对浏览器本身,让一切你所需要的元素与交互,从这里信手拈来。
Flask + Vue
【2021-11-25】浅谈如何用使用flask和vue,快速开发常用应用, flask是python的一种通用的web框架,诞生至今已有10年了,虽然官网界面比较复古极简,但使用者还是不在少数。纯后端的api开发,还可以看向fastapi,都是当今最主流的两个选择。
flask和vue结合的优势
- vue有着简洁、易懂的前端界面开发逻辑
- flask有着python独特的语义化代码,非常适合处理各种数据
- 两种语言都对小白非常友好,python更是当下最广泛的编程语言,用户量庞大
- 当前vue在vite的帮助下,可以快速定制开发环境,不论是html模板的pug语法,还是style的stylus语法,都是简化输入,突出逻辑框架,开发者的精力可以更集中在逻辑设计上。
- 容易上手,带来的自然高效率、易维护、易复制
数据库代码:
-- SQLite
CREATE TABLE books (
id int,
title varcha(255),
author varcha(255),
price int
);
-- 插入数据
INSERT INTO books VALUES ('1','商业周刊','期刊','15');
INSERT INTO books VALUES ('2','新闻周刊','新闻','25');
INSERT INTO books VALUES ('3','有机化学','书籍','46');
INSERT INTO books VALUES ('4','读者文摘','读者','48');
flask入口文件app.py
import sqlite3
from flask import Flask
from flask import jsonify,render_template
from flask_cors import CORS
app = Flask(__name__)
# CORS(app, supports_credentials=True) #解决跨域问题
cors = CORS(app, resources={r"/api/*": {"origins": "*"}}) #两种模式都行
@app.route('/')
def home():
return render_template('index.html',title='flask & vue')
@app.route('/api/books')
def books():
conn = sqlite3.connect('books.db')
conn.row_factory = sqlite3.Row
cur = conn.cursor()
sql = 'select * from books'
rows = cur.execute(sql).fetchall()
rows = [dict(row) for row in rows]
return jsonify(rows)
if __name__ == "__main__":
app.run(debug=True,port=3000)
前端文件:index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 引入vue -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 引入axios -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<h1>书籍信息展示</h1>
<table border="1" >
<tr>
<td>#</td>
<td>标题</td>
<td>作者</td>
<td>价格</td>
</tr>
<!-- 定义行 -->
<tr v-for="book in books">
<td>[[book.id]]</td>
<td>[[book.title]]</td>
<td>[[book.author]]</td>
<td>[[book.price]]</td>
</tr>
</table>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
books:[],
msg: '说你好'
},
delimiters: ["[[","]]"], //用于避免与flask冲突
mounted: function(){
this.fetchData()
},
methods: {
fetchData(){ // axios异步请求数据
axios.get('/api/books').then(res =>{
this.books = res.data
console.log(this.books)
}).catch(err=>{
console.log(err)
})
}
}
})
</script>
</body>
</html>
最终效果
- 由于flask采用的是jinja模板,也就是采用{{} }模式与web页面交互,因此会与vue的默认分隔符号相冲突,因此在script里需要修改delimiters: [ “[[”,” ]]”]。当然还有其他修改方式,这里推荐的也是相对简单的方法。
TypeScript
JavaScript 与 TypeScript 的区别
- TypeScript 是 JavaScript 的
超集
,扩展了 JavaScript 的语法,因此现有的 JavaScript 代码可与 TypeScript 一起工作无需任何修改,TypeScript 通过类型注解提供编译时的静态类型检查。 - TypeScript 可处理已有的 JavaScript 代码,并只对其中的 TypeScript 代码进行编译。
安装
# 已安装 npm
# 使用国内镜像:
npm config set registry https://registry.npmmirror.com
# 安装 typescript:
npm install -g typescript
tsc -v # Version 3.2.2
执行过程
- (1)
.ts
作为 TypeScript 代码文件扩展名 - (2) 将 TypeScript 转换为 JavaScript 代码
- 命令:
tsc app.ts
- 当前目录下(与 app.ts 同一目录)就会生成一个 app.js 文件
- 命令:
- (3) node 命令来执行
app.js
文件 -node app.js
使用
- llm.ts
- cursive
import { useCursive } from 'cursive-gpt'
const cursive = useCursive({
openAI: {
apiKey: 'sk-xxxx'
}
})
const { answer } = await cursive.ask({
prompt: 'What is the meaning of life?',
})