- A+
前端技术栈+Vue笔记
ES6新特性
1.let
1)let声明有严格的局部作用域
此时"console.log("job= "+job)"将报错
{ var name = "zy学习"; let job = "java工程师"; console.log("name= "+name) console.log("job= "+job) } console.log("name2= "+name) console.log("job= "+job)
2)let只能声明一次
此时业因为let的重复声明
会报错SyntaxError (语法错误):redeclaration of let num2
//let 只能声明1次 var num1 = 100; var num1 = 200; console.log(num1); let num2 = 100; let num2 = 200; console.log(num2);
3)当var变量 定义在后面,不会报错未定义,而是提升变量为undefind。
let变量则不会,会毫不留情的报错
//let不存在变量提升 var存在变量提升 console.log("x=",x); var x = "tom"; console.log("z=",z); let z = "zzz";
2.count
1)常量在定义时,需要赋值
//常量在定义时,需要赋值 const PI=3.14;//SyntaxError: missing = in const declaration console.log("PI= ",PI)
2)常量赋值后不能修改
会报错 invalid assignment to const 'PI'
const PI=3.14; PI = 3.14159256;
3.解构赋值
3.1 数组解构
1)传统方法
let arr = [1, 2, 3]; //解构(取出数据): let x = arr[0], y = arr[1], z = arr[2]; console.log("x= " + x + " ,y= " + y + " ,z= " + z);
2)ES6
let [a,b,c] = arr; console.log("a= " + a + " ,b= " + b + " ,c= " + c); let [n1,n2,n3] = [100,200,300]; console.log("n1= " + n1 + " ,n2= " + n2 + " ,n3= " + n3);
3.2 对象解构
注意事项:
1.{name,age}中的name,age 名字要和monster中的对象属性名保持一致
2.使用{ } 不要使用[ ]
3.{name,age}顺序无所谓
1)传统方法
//传统 对象名.属性名 let monster = {name: '牛魔王', age: 880} console.log(monster.name," ",monster.age)
2)ES6
let {name,age} = monster; console.log("name= ",name," ",",age= ",age) console.log("age= ",age," ",",name= ",name) let {name,age} = {name: '牛魔王', age: 880}
方法的形参对象也可以解构
function f1(name,age){ console.log("f1-name= ",name," ",",f1-age= ",age) } f1(monster)
3.3 方法解构
4.模板字符串
注意事项:
1.反引号 ``包裹
2.可作为普通字符串使用
3.可以原生输出代码 (意思是不需要加很多 n 拼接字符串)
let str1 = `for(int i = 0 ;i <10 ; i++){ System.out.println("i= "+i); }`; console.log("str1=", str1)
4.字符串插入变量和表达式,使用${ }
*类似于el表达式
let name = "zy88"; let str2 = `学习=${name}`; let str3 = `1+2=${1 + 2}`; let n1 = 80; let n2 = 20; let str4 = `n1+n2=${n1 + n2}`; console.log("str2=", str2) console.log("str3=", str3) console.log("str4=", str4)
5.字符串中调用函数
function sayHi(name) { return "hi "+name; } let name2 = 'tom' let str5 = `sayHi()返回结果= ${sayHi(name2)}` console.log("str5=", str5)
5.对象相关新特性
注意事项:
1.自动从上面找到相应变量
2.对象方法简写
1)传统对方法的定义
let monster = { name:"红孩儿", age:100, sayHi:function () { console.log("信息:name=",this.name,"age=",this.age) } } monster.sayHi();
2)ES6对方法的定义
let monster2 = { name:"红孩儿~", age:900, sayHi() { console.log("信息:name=",this.name,"age=",this.age) } }
3.对象扩展运算符--拷贝
1)传统拷贝
let cat2 = cat; cat2.name = "大花猫" console.log("cat=>",cat) console.log("cat2=>",cat2)
2)ES6深拷贝
let cat2 = {...cat};//深拷贝 cat2.name = "中花猫" console.log("cat=>",cat) console.log("cat2=>",cat2)
3)ES6并对象
let monster = {name:"白骨精",age:100} let car = {brand:"xiaomi",price:149000} let monster_car = {...monster,...car}
6.箭头函数
1)基本语法:
(参数列表)=> {
函数体...
}
2)注意事项:
1.没有参数或多个参数用括号( )括起来,一个参数可以省略括号
2.函数体只有一行语句,并需要返回结果时,可以省略花括号{},结果自动返回
3)对比传统
a)传统
var f1 = function (n) { return n * 2; } console.log(f1(2))
a)ES6
let f2 = (n) => { return n * 2; } // console.log(f2) console.log(f2(3)) //简化 let f3 = n => n * 3; console.log(f3(10))
b)传统
var f1 = function (n,m) { var res = 0; for (var i = n; i <=m; i++) { res += i } return res } console.log(f1(1,10))
b)ES6
let f2 = (n,m) => { var res = 0; for (var i = n; i <=m; i++) { res += i } return res } // console.log(f2) console.log(f2(1,10))
4)箭头函数+解构
- f2传入对象monster
- f2形参时skill,所以根据es6对象解构特性,会把monster对象的skill赋给skill
- 对象解构的前提是形参skill和monster对象属性 skill的属性名保持一致
const monster = { name:"红孩儿", age:10000, skill:['红缨枪','三味真火'] } //传统解构 function f1(monster) { console.log("skill=",monster.skill) } f1(monster) //ES6 let f2 = ({skill}) =>{ console.log("skill=",skill); } f2(monster)
7.promise
promise的引出
promise是为了解决传统ajax异步调用需要多个操作时,会导致回调函数嵌套引起代码冗余的问题
原生的jquery 对于需要多次异步请求时表现:
<script type="text/javascript"> $.ajax({ url: "data/monster.json", success(resultData) { console.log("第一次ajax请求 monster基本信息= ", resultData); $.ajax({ url: `data/monster_detail_${resultData.id}.json`, success(resultData) { console.log("第二次ajax请求 monster详细信息= ", resultData); }, error(err) { console.log("出现异常= ", err) } }) }, error(err) { console.log("出现异常= ", err) } }) </script>
可以看出代码有非常多的嵌套,很不美观。
使用promise来完成多次ajax请求时表现:
先请求到monster.json
1. 创建Promise对象
2. 构造函数传入一个箭头函数
3. (resolve, reject) 参数列表resolve: 如果请求成功, 调用resolve函数
4. 如果请求失败, 调用reject函数
5. 箭头函数体, 仍然是通过jquery发出ajax
<script type="text/javascript"> let p = new Promise((resolve, reject) => { //发出ajax $.ajax({ url: "data/monster.json", success(resultData) {//成功的回调函数 console.log("promise发出的第1次ajax monster基本信息=", resultData); resolve(resultData); }, error(err) { //console.log("promise 1发出的异步请求异常=", err); reject(err); } }) }) //这里我们可以继续编写请求成功后的业务 p.then((resultData) => { //这里我们可以继续发出请求 //console.log("p.then 得到 resultData", resultData); return new Promise((resolve, reject) => { $.ajax({ url:`data/monster_detail_${resultData.id}.json`, success(resultData) { //第2次ajax请求成功,回调函数 console.log("第2次ajax请求 monster的详细信息=", resultData); //继续进行下一次的请求 resolve(resultData); }, error(err) { //第2次ajax请求失败,回调函数 //console.log("promise2 发出的异步请求异常=", err); reject(err); } }) }) }).then((resultData) => { console.log("p.then().then(), resultData", resultData) //即可以在这里发出第3次ajax请求=》 获取该妖怪的女友 return new Promise((resolve, reject) => { $.ajax({ url: `data/monster_gf_${resultData.gfid}.json`, success(resultData) { //第3次ajax请求成功,回调函数 console.log("第3次ajax请求 monster女友的详细信息=", resultData); //继续进行下一次的请求 //resolve(resultData); }, error(err) { //第2次ajax请求失败,回调函数 //console.log("promise2 发出的异步请求异常=", err); //reject(err); } }) }) }).catch((err) => { //这里可以对多次ajax请求的异常进行处理 console.log("promise异步请求异常=", err); }) </script>
使用了promise后 将传统的嵌套模式,改成了链式调用。
但代码依旧是否冗余,因此我们可以抽取相同的部分。
promise 代码优化重排
首先我们可以抽取一个工具方法
function get(url, data) { return new Promise((resolve, reject) => { $.ajax({ url: url, data: data, success(resultData) { resolve(resultData); }, error(err) { reject(err); } } ) }) }
之后调用此方法完成业务即可
get("data/monster.json").then((resultData) => { //第1次ajax请求成功后的处理代码 console.log("第1次ajax请求返回数据=", resultData); return get(`data/monster_detail_${resultData.id}.json`); }).then((resultData) => { //第2次ajax请求成功后的处理代码 console.log("第2次ajax请求返回数据=", resultData); //return get(`data/monster_detail_${resultData.id}.json`); return get(`data/monster_gf_${resultData.gfid}.json`); }).then((resultData) => { //第3次ajax请求成功后的处理代码 console.log("第3次ajax请求返回数据=", resultData); //继续.. }).catch((err) => { console.log("promise请求异常=", err); })
8.模块化编程
- 传统非模块化开发有如下的缺点:(1)命名冲突(2)文件依赖[代码演示]
- Javascript 代码越来越庞大,Javascript 引入模块化编程,开发者只需要实现核心的业务逻辑,其他都可以加载别人已经写好的模块
- Javascript 使用"模块"(module)的概念来实现模块化编程, 解决非模块化编程问题
模块化编程分类
1.CommonJS 模块化规范/ES5 的写法
2.ES6 模块化规范
CommonJS 模块化规范/ES5 的写法
规则
-
每个js 文件就是一个模块,有自己的作用域。在文件中定义的变量、函数、类/对象,
都是私有的,对其他js 文件不可见 -
CommonJS 使用module.exports={} / exports={} 导出模块, 使用let/const 名称=
require("xx.js") 导入模块
图解
代码
这是 "function.js":
//这是function.js: //定义对象,变量,常量,函数 const sum = function (a, b) { return parseInt(a) + parseInt(b); } const sub = function (a, b) { return parseInt(a) - parseInt(b); } let name = "zy学习"; const PI = 3.14; const monster = { name:"牛魔王", age:500, hi(){ console.log("Hi,i am 牛魔王~") } } //导出 module.exports = { sum:sum, sub,sub, myName,name }
这是 "use.js":
//导入 const m = require("./function") //使用 console.log(m.sum(100,200)) console.log(m.sub(120,60)) console.log(m.myName)
ES6 模块化规范 写法
规则
1、ES6 使用(1)export {名称/对象/函数/变量/常量} (2) export 定义= (3) export default {}
导出模块
2、使用import {} from "xx.js" / import 名称form "xx.js" 导入模块
图解
代码
导出:
const cat = { name:"小白", age:3, cry(){ console.log("小猫喵喵叫~") } } const dog = { name:"大黄", age:5, hi(){ console.log("大黄 对你说 hi~") } } //1.使用批量导出 export { cat, dog }
//2.创建时直接导出 export const cat = { name:"小白", age:3, cay(){ console.log("小猫喵喵叫~") } } const dog = { name:"大黄", age:5, hi(){ console.log("大黄 对你说 hi~") } }
//3.默认方式导出 export default { cat: { name: "小白", age: 3, cay() { console.log("小猫喵喵叫~") } }, dog: { name: "大黄", age: 5, hi() { console.log("大黄 对你说 hi~") } } }
导入
//1 import {cat,dog} from "./hspcommon"; cat.cry(); dog.hi() //2. import {cat} from "/./hspcommon2" cat.name //3. import m from "./hspcommon3" m.cat.cay()
Vue
基本介绍
- Vue 是一个前端框架, 易于构建用户界面
- Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或项目整合
- 支持和其它类库结合使用
- 开发复杂的单页应用非常方便
- Vue 是Vue.js 的简称
MVVM思想
- M∶即Model,模型,包括数据和一些基本操作
- V∶即View,视图,页面渲染结果
- VM∶即View-Model,模型与视图间的双向操作(无需开发人员干涉)
- 在MVVM之前,开发人员从后端获取需要的数据模型,然后要通过DOM 操作Model
渲染到View 中。而后当用户操作视图,我们还需要通过DOM获取View 中的数据,
然后同步到Model 中。 - 而MVVM中的VM 要做的事情就是把DOM 操作完全封装起来,开发人员不用再关心
Model 和View 之间是如何互相影响的 - 只要我们Model 发生了改变,View上自然就会表现出来
- 当用户修改了View,Model 中的数据也会跟着改变
- 结果:把开发人员从繁琐的DOM操作中解放出来,把关注点放在如何操作Model上, 大
大提高开发效率
Vue语法
插值表达式
- {{message}} : 插值表达式
- message 就是从model 的data 数据池来设置
- 当我们的代码执行时,会到data{} 数据池中去匹配数据, 如果匹配上, 就进行替换
, 如果没有匹配上, 就是输出空
//
欢迎你{{message}}-{{name}}
let vm = new Vue({
el: "#app", //创建的vue 实例挂载到id=app 的div
data: { //data{} 表示数据池(model 的有了数据), 有很多数据,以k-v 形式设置(根据业务
需要来设置)
message: "Hello-Vue!",
name:"zy"
}
})
数据单向渲染
- v-bind 指令可以完成基本数据渲染/绑定
- v-bind 简写形式就是一个冒号(:)
1. 使用插值表达式引用 data数据池数据是在标签体内 2. 如果是在标签/元素 的属性上去引用data数据池数据时,不能使用插值表达式 3. 需要使用v-bind, 因为v-bind是vue来解析, 默认报红,但是不影响解析
//<img v-bind:src="img_src" v-bind:width="img_width"> //<img :src="img_src" :width="img_width">
数据双向渲染
-
v-bind是数据单向渲染: data数据池绑定的数据变化,会影响view
-
v-model="hobby.val" 是数据的双向渲染,
- data数据池绑定的数据变化,会影响view 【底层的机制是 Data Bindings】
- view 关联的的元素值变化, 会影响到data数据池的数据【底层机制是Dom Listeners】
//<input type="text" v-model="hobby.val"><br/><br/>
事件绑定
- v-on:click 表示我们要给button元素绑定一个click的事件
- 底层仍然是dom处理
- 如果方法不需要传递参数,可以省略()
- v-on:click可以简写@, 但是需要浏览器支持
<button v-on:click="sayHi()">点击输出</button> <button @click="sayOk">点击输出</button> let vm = new Vue({ el: "#app", //创建的vue实例挂载到 id=app的div, el 就是element的简写 data: { //data{} 表示数据池(model中的数据), 有很多数据 ,以k-v形式设置(根据业务需要来设置) message: "Vue事件处理的案例", name: "zzz" }, // 1. 是一个methods属性, 对应的值是对象{} // 2. 在{} 中, 可以写很多的方法, 你可以这里理解是一个方法池 // 3. 这里需要小伙伴有js的基础=>java web第4章 methods: { sayHi() { console.log("hi, 银角大王~"); }, sayOk() { console.log("ok, 金角大王~"); } } })
修饰符
- 修饰符(Modifiers) 是以(.)指明的后缀,指出某个指令以特殊方式绑定
- 例如,.prevent 修饰符告诉v-on 指令对于触发的事件调用event.preventDefault()即阻
止事件原本的默认行为 - 事件修饰符
.stop 阻止事件继续传播
.prevent 阻止标签默认行为
.capture 使用事件捕获模式,即元素自身触发的事件先在此处处理,然后才交由内部元素进
行处理
.self 只当在event.target 是当前元素自身时触发处理函数
.once 事件将只会触发一次
.passive 告诉浏览器你不想阻止事件的默认行为 - 键盘事件的修饰符
比如: 项目经常需要监听一些键盘事件来触发程序的执行,而Vue 中允许在监听的时候添
加关键修饰符
- v-model 的修饰符
比如: 自动过滤用户输入的首尾空格
<button v-on:click.once="onMySubmit">点击一次</button><br/> <input type="text" v-on:keyup.enter="onMySubmit"> <input type="text" v-on:keyup.down="onMySubmit"> <input type="text" v-model.trim="count">
条件渲染
v-if
<input type="checkbox" v-model="sel">是否同意条款[v-if 实现] <h1 v-if="sel">你同意条款</h1> <h1 v-else>你不同意条款</h1>
v-show
<input type="checkbox" v-model="sel">是否同意条款[v-show 实现] <h1 v-show="sel">你同意条款</h1> <h1 v-show="!sel">你不同意条款</h1>
v-if VS v-show
- v-if 会确保在切换过程中,条件块内的事件监听器和子组件销毁和重建
- v-show 机制相对简单, 不管初始条件是什么,元素总是会被渲染,并且只是对CSS 进行切换
- 使用建议:如果要频繁地切换,建议使用v-show ;如果运行时条件很少改变,使用v-if 较好
列表渲染
Vue 提供了v-for 列表循环指令
1、对数组进行遍历
2、用v-for 来遍历一个对象的property
<h1>简单的列表渲染-带索引</h1> <ul> <li v-for="(i,index) in 3">{{i}}-{{index}}</li> </ul> <table width="400px" border="1px"> <tr v-for="(monster,index) in monsters"> <td>{{index}}</td> <td>{{monster.id}}</td> <td>{{monster.name}}</td> <td>{{monster.age}}</td> </tr> </table>
组件化编程
- 组件(Component) 是Vue.js 最强大的功能之一(可以提高复用性[1.界面2.业务处理])
- 组件也是一个Vue实例,也包括∶ data、methods、生命周期函数等
- 组件渲染需要html模板,所以增加了template 属性,值就是HTML 模板
- 对于全局组件,任何vue 实例都可以直接在HTML 中通过组件名称来使用组件
- data 是一个函数,不再是一个对象, 这样每次引用组件都是独立的对象/数据
全局组件
1、定义一个全局组件, 名称为counter
- {} 表示就是我们的组件相关的内容
- template 指定该组件的界面, 因为会引用到数据池的数据,所以需要是模板字符串
- 要把组件视为一个Vue 实例,也有自己的数据池和methods
- 对于组件,我们的数据池的数据,是使用函数/方法返回[目的是为了保证每个组件的数据是独立], 不能使用原来的方式
- 这时我们达到目前,界面通过template 实现共享,业务处理也复用
- 全局组件是属于所有vue 实例,因此,可以在所有的vue 实例使用
Vue.component("counter", { template: `<button v-on:click="click()">点击次数= {{count}} 次【全局组件化】</button>`, data() {//这里需要注意,和原来的方式不一样!!!! return { count: 10 } }, methods: { click() { this.count++; } } })
局部组件
- 可以把常用的组件,定义在某个commons.js中 export
- 如果某个页面需要使用, 直接import
const buttonCounter = {//定义一个组件, 组件的名称为 buttonCounter template: `<button v-on:click="click()">点击次数= {{count}} 次【局部组件化】</button>`, data() {//这里需要注意,和原来的方式不一样!!!! return { count: 10 } }, methods: { click() { this.count++; } } } //创建Vue实例,必须有 let vm = new Vue({ el: "#app",//Vue实例的挂载点 components: { //引入/注册某个组件, 此时my_counter就是一个组件, 是一个局部组件,他的使用范围在当前vue 'my_counter': buttonCounter } })
vue生命周期&钩子函数
- Vue 实例有一个完整的生命周期,也就是说从开始创建、初始化数据、编译模板、挂载
DOM、渲染-更新-渲染、卸载等一系列过程,我们称为Vue 实例的生命周期 - 钩子函数(监听函数): Vue 实例在完整的生命周期过程中(比如设置数据监听、编译模
板、将实例挂载到DOM 、在数据变化时更新DOM 等), 也会运行叫做生命周期钩子的函
数 - 钩子函数的作用就是在某个阶段, 给程序员一个做某些处理的机会
- new Vue()
new 了一个Vue 的实例对象,此时就会进入组件的创建过程。 - Init Events & Lifecycle
初始化组件的事件和生命周期函数 - beforeCreate
组件创建之后遇到的第一个生命周期函数,这个阶段data 和methods 以及dom 结构都未
被初始化,也就是获取不到data 的值,不能调用methods 中的函数 - Init injections & reactivity
这个阶段中, 正在初始化data 和methods 中的方法 - created
- 这个阶段组件的data 和methods 中的方法已初始化结束,可以访问,但是dom 结构未
初始化,页面未渲染 - 在这个阶段,经常会发起Ajax 请求
- 编译模板结构(在内存)
- beforeMount
当模板在内存中编译完成,此时内存中的模板结构还未渲染至页面上,看不到真实的数据 - Create vm.$el and replace ‘el’ with it
这一步,再在把内存中渲染好的模板结构替换至真实的dom 结构也就是页面上 - mounted
此时,页面渲染好,用户看到的是真实的页面数据, 生命周期创建阶段完毕,进入到了运
行中的阶段 - 生命周期运行中
10.1 beforeUpdate
当执行此函数,数据池的数据新的,但是页面是旧的
10.2 Virtual DOM re-render and patch
根据最新的data 数据,重新渲染内存中的模板结构,并把渲染好的模板结构,替换至页面
上
10.3 updated
页面已经完成了更新,此时,data 数据和页面的数据都是新的 - beforeDestroy
当执行此函数时,组件即将被销毁,但是还没有真正开始销毁,此时组件的data、methods
数据或方法还可被调用 - Teardown……
注销组件和事件监听 - destroyed
组件已经完成了销毁
Vue Cli脚手架
项目文件结构
Vue 请求页面执行流程
- 整个页面渲染过程中,main.js 是中心,也是连接各个组件,路由器的关键
通过修改成完整的写法, 清晰思路
D:vue_projectvue_project_quickstartsrcmain.js import Vue from 'vue' import App from './App' //完整写法是import App from './App.vue' import router from './router'//完整写法是import router from './router/index.js' Vue.config.productionTip = false new Vue({ el: '#app', //这里的#app 是挂到index.html 的<div id="app"></div> router, //完整写法是router: router, 第二个router 是import router[这里] from './router' components: {App }, //完整写法是components: { 'App':App } 因为名字相同可以省略'App' template: '<App/>' //这里的'<App/>' 的App 就是上面components 引入的组件的名字
ElementUI
ElementUI 官网: https://element.eleme.cn/#/zh-CN
ElementUI 是组件库,网站快速成型工具
Axios
- axios 是独立于vue 的一个项目,不是Vue 的一部分
- axios 通常和Vue 一起使用,实现Ajax 操作
- Axios 是一个基于promise 的HTTP 库
<script> new Vue({ el: "#app", data: { msg: "妖怪信息列表", monsterList: [] //表示妖怪的信息数组 }, methods: {//自定义方法 list() {//发送ajax请求,获取数据 axios /* 1. axios.get() 表示发出ajax请求 2. http://localhost:63342/axios/data/response.data.json 表示请求的url 要根据实际情况来填写 3. axios发出ajax请求的基本语法 axios.get(url).then(箭头函数).then(箭头函数)...catch(箭头函数) (1) 如果get请求成功就进入到第一个then() (2) 可以再 第一个then()中继续发出axios的ajax请求 (3) 如果有异常, 会进入到 catch(箭头函数) 4. list在生命周期函数created() 中调用-自己去回顾vue的生命周期函数 */ axios.get("http://localhost:63342/axios/data/response.data.json") .then(responseData => { console.log("responseData= ", responseData) //使用JSON.stringify(json) 把json对象转成一个字符串,方便观察 console.log("responseData= ", JSON.stringify(responseData)); console.log("responseData.data.data.item= ", responseData.data.data.items) //将妖怪列表数组信息, 绑定到 data数据池的 monsterList //要学会看返回的数据格式!!! this.monsterList = responseData.data.data.items; //可以再次发出ajax请求 // return axios.get("http://localhost:63342/axios/data/response.data.json") }) // .then(responseData => { // console.log("第二次axios发出 ajax请求responseData= ", responseData) // }) .catch(err => { console.log("异常=", err) }) } }, created() { this.list(); } }) </script>
将JSON 对象转成JSON.stringify(response)
-
将JSON 对象转成JSON.stringify(response)
-
格式化输出JSON 字符串,方便观察分析
本文学习内容来自韩顺平老师的课程
仅供个人参考学习