谷粒商城笔记合集
六、前端开发基础知识
6.1 VSCode 使用
6.1.1 下载安装
-
下载VsCode:https://code.visualstudio.com/
-
安装VsCode
-
VsCode安装插件
-
Auto Close Tag:自动闭合HTML/XML标签
-
Auto Rename Tag:自动完成另一侧标签的同步修改
-
Chinese(Simplified)
-
ESLint:语法纠错
-
配置 setting.json
打开 VSCode 左上角文件-首选项-设置,在设置中搜索eslint,点击并翻页到最下面,点击setting.json进行配置并保存:
{ "workbench.colorTheme": "Visual Studio Dark", // 值设置为true时,每次保存的时候自动格式化;值设置为false时,代码格式化请按shift+alt+F "editor.formatOnSave": true, // 每次保存的时候将代码按eslint格式进行修复: "eslint.validate": [ "javascript", "javascriptreact", "html", "vue" ], "eslint.enable": true, "eslint.run": "onType", "eslint.options": { "extensions": [ "js", "vue", ".jsx", ".tsx" ] }, "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, "eslint.format.enable": true, "eslint.lintTask.enable": true, "[vue]": { "editor.defaultFormatter": "dbaeumer.vscode-eslint" }, }
-
在任意文件:鼠标右键->使用…格式化文档->配置默认格式程序->选择eslint
这样之后 alt+Shift+f 之后就是按照 eslint 规则保存
-
-
HTML CSS Support:让 html 标签上写class 智能提示当前项目所支持的样式
-
HTML Snippets
-
JavaScript(ES6):ES6 语法智能提示以及快速输入,除j外还支持.ts, .jsx, .tsx, .html, .vue;省去了配置其支持各种包含is代码文件的时间
-
Live server
-
open in browser:直接右键项目单击启动
-
Vetur:语法高亮,智能感知 包含格式化功能,Alt+Shift+F (格式化全文) ,Ctrl+K Ctrl+F (格式化选中代码,两个Ctrl需要同时按着)
-
Vue 2 Snippets:vue语法提示
-
-
重启VsCode
6.1.2 创建项目
vscode 很轻量级,本身没有新建项目的选项,创建一个空文件夹就可以当做一个项目
6.1.3 创建网页
-
新建文件,命名为 index.html
-
快捷键 ! ,快速创建网页模板
-
h1 + 回车,自动补全标签
6.1.4 运行
6.1.5 快捷键
ALT+SHIFT+f //代码格式化
6.1.6 用户代码片段
Visual Studio Code —> 文件 —> 首选项 —> 配置用户 —> 代码片段
{
"http-get 请求": {
"prefix": "httpget",
"body": [
"this.\\$http({",
"url: this.\\$http.adornUrl(''),",
"method: 'get',",
"params: this.\\$http.adornParams({})",
"}).then(({data}) => {",
"})"
],
"description": "httpGET 请求"
},
"http-post 请求": {
"prefix": "httppost",
"body": [
"this.\\$http({",
"url: this.\\$http.adornUrl(''),",
"method: 'post',",
"data: this.\\$http.adornData(data, false)",
"}).then(({ data }) => { });"
],
"description": "httpPOST 请求"
},
"vue": {
"prefix": "vue",
"body": [
"<template>",
" <div class=''></div>",
"</template>",
"",
"<script>",
"// 这里可以导入其他文件(比如:组件,工具 js,第三方插件 js,json文件,图片文件等等)",
"// 例如:import 《组件名称》 from '《组件路径》';",
"",
"export default {",
" // import 引入的组件需要注入到对象中才能使用",
" components: {},",
" props: {},",
" data () {",
" return {",
"",
" }",
" },",
" computed: {},",
" watch: {},",
" methods: {",
"",
" },",
" // 生命周期 - 创建完成(可以访问当前 this 实例)",
" created () {",
"",
" },",
" // 生命周期 - 挂载完成(可以访问 DOM 元素)",
" mounted () {",
"",
" },",
" beforeCreate () {},",
" beforeMount () {},",
" beforeUpdate () {},",
" updated () {},",
" beforeDestroy () {},",
" destroyed () {},",
" activated () {}",
"}",
"</script>",
"",
"<style lang='scss' scoped>",
" // @import url($3); 引入公共 css 类",
" $4",
"</style>"
],
"description": "生成 vue 模板"
}
}
6.2 ES6新特性(一种标准)💡
6.2.1 ES6介绍
什么是ES
来看下前端的发展历程:
-
web1.0 时代:
最初的网页以 HTML 为主,是纯静态的网页。网页是只读的,信息流只能从服务的到客户端单向流通。开发人员也只关心页面的样式和内容即可。
-
web2.0 时代:
- 1995 年,网景工程师 Brendan Eich 花了 10 天时间设计了 JavaScript 语言。
- 1996 年,微软发布了 JScript,其实是 JavaScript 的逆向工程实现。
- 1996 年 11 月,JavaScript 的创造者 Netscape 公司,决定将 JavaScript 提交给标准化组织 ECMA,希望这种语言能够成为国际标准。
- 1997 年,ECMA 发布 262 号标准文件(ECMA-262)的第一版,规定了浏览器脚本语言的标准,并将这种语言称为 ECMAScript,这个版本就是 1.0 版。JavaScript 和 JScript 都是
ECMAScript
的标准实现者,随后各大浏览器厂商纷纷实现了ECMAScript
标准。
所以,ECMAScript 是浏览器脚本语言的规范,而各种我们熟知的 js 语言,如 JavaScript 则是规范的具体实现。
ES6概述
ECMAScript 6.0(以下简称 ES6,ECMAScript 是一种由 Ecma 国际(前身为欧洲计算机制造商协会,英文名称是 European Computer Manufacturers Association)通过 ECMA-262 标准化的脚本程序设计语言)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了,并且从 ECMAScript 6 开始,开始采用年号来做版本。即 ECMAScript 2015,就是 ECMAScript6。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。每年一个新版本。
6.2.2 let声明变量
-
var 声明的变量往往会越域;let 声明的变量有严格局部作用域
{ var a=1; let b=2; } console.log(a); // 1 console.log(b); // Uncaught ReferenceError: b is not defined
-
var 可以声明多次;let 只能声明一次
var m=1; var m=2; let n=1; // 编译出错 Cannot redeclare block-scoped variable 'n' let n=2; // 编译出错 Cannot redeclare block-scoped variable 'n'
-
var 会变量提升;let 不存在变量提升
console.log(x); // undefined var x=10; console.log(y); // Uncaught ReferenceError: can't access lexical declaration 'y' before initialization let y=10;
6.2.3 const声明只读常量
-
一旦声明必须初始化,否则编译报错
const a; // 'const' declarations must be initialized
-
声明之后不允许改变
const a=10; a=20; console.log(a); // Uncaught TypeError: invalid assignment to const 'a'
6.2.4 解构表达式
1)数组解构
let arr = [1,2,3];
//let a=arr[0]; 以前的做法
//let b=arr[1];
//let c=arr[2];
const [a,b,c] = arr;
console.log(a,b,c);
2)对象解构
const person = {
name: "jack",
age: 21,
language: ['java', 'js', 'css']
}
// const name = person.name; //以前的做法
// const age = person.age;
// const language = person.language;
const { name, age, language } = person;
console.log(name);
console.log(age);
console.log(language);
//扩展:重命名属性名
const { name: nn, age, language } = person;
console.log(nn);
console.log(age);
console.log(language);
6.2.5 字符串扩展
1)几个新的 API
- includes(string):判断原字符串是否包含参数字符串。
- startsWith(string):判断参数字符串是否在原字符串的头部
- endsWith(string):判断参数字符串是否在原字符串的尾部
let str = "hello.vue";
console.log(str.startsWith("hello")); // true
console.log(str.endsWith(".vue")); // true
console.log(str.includes("e")); // true
console.log(str.includes("hello")); // true
2)模板字符串
模板字符串相当于加强版的字符串,用反引号 ` ,可以用来定义
-
普通字符串
-
多行字符串
//定义多行字符串 let ss = ` <div> <span>hello world<span> </div> `
-
加入变量和表达式
let name = "张三"; let age = 18; function fun() { return "这是一个函数" } //加入变量和表达式 let info = `我是${name},今年${age}了,我想说:${fun()}`; console.log(info); // 我是张三,进能18了,我想说:这是一个函数
6.2.6 函数优化
1)参数默认值
//function add(a, b) { 以前的做法
// b = b || 1;
// return a + b;
//}
//直接给参数写上默认值,没传就会自动使用默认值
function add(a , b = 1) {
return a + b;
}
console.log(add(10)); // 11
2)不定参数
function fun(...values) {
console.log(values.length)
}
fun(1, 2) // 2
fun(1, 2, 3, 4) // 4
3)箭头函数
// var print = function (obj) { 以前的做法:一个参数
// console.log(obj);
// }
var print = obj => console.log(obj);
//var sum = function (a, b) { 以前的做法:多个参数
// return a + b;
//}
var sum2 = (a, b) => a + b;
//var sum = function (a, b) { 以前的做法:多行方法体
// c = a + b;
// return c;
//}
var sum3 = (a, b) => {
c = a + b;
return c;
};
实战:箭头函数+对象解构
const person = {
name: "jack",
age: 21,
language: ['java', 'js', 'css']
}
//function hello(person) { 以前的做法
// console.log("hello," + person.name)
//}
var hello2 = ({ name }) => { console.log("hello," + name) };
6.2.7 对象优化
1)新增的API
- keys(obj):获取对象的所有 key 形成的数组
- values(obj):获取对象的所有 value 形成的数组
- entries(obj):获取对象的所有 key 和 value 形成的二维数组
- assign(dest, …src) :将多个 src 对象的值 拷贝到 dest 中。(第一层为深拷贝,第二层为浅拷贝)
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
const person = {
name: "jack",
age: 21,
language: ['java', 'js', 'css']
}
console.log(Object.keys(person)); // ["name", "age", "language"]
console.log(Object.values(person)); // ["jack", 21, Array(3)]
console.log(Object.entries(person)); // [Array(2), Array(2), Array(2)]
Object.assign(target, source1, source2);
console.log(target) // {a: 1, b: 2, c: 3}
2)声明对象简写
const age = 23
const name = "张三"
//const person1 = { age: age, name: name } 以前的做法
const person1 = { age, name }
3)对象的函数属性简写
let person = {
name: "jack",
//eat: function (food) { 以前的做法
// console.log(this.name + "在吃" + food);
//},
// 箭头函数版:这里拿不到 this
eat2: food => console.log(person.name + "在吃" + food),
// 简写版:
eat3(food) {
console.log(this.name + "在吃" + food);
}
}
person.eat3("apple"); //jack在吃apple
4)对象扩展运算符
// 1、拷贝对象(深拷贝)
let person1 = { name: "Amy", age: 15 }
let someone = { ...person1 }
console.log(someone) //{name: "Amy", age: 15}
// 2、合并对象
let age = { age: 15 }
let name = { name: "Amy" }
let person2 = { ...age, ...name } //如果两个对象的字段名重复,后面对象字段值会覆盖前面对象的字段值
console.log(person2) //{age: 15, name: "Amy"}
6.2.8 map和reduce
1)map
map(function):接收一个函数,将原数组中的所有元素用这个函数处理后放入新数组返回
let arr = ['1', '20', '-5', '3'];
console.log(arr) // [ "1", "20", "-5", "3" ]
arr = arr.map(s => parseInt(s));
console.log(arr) // [ 1, 20, -5, 3 ]
2)reduce
arr.reduce(callback,[initialValue]):为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce 的数组。
-
callback :执行数组中每个值的函数,包含四个参数
- previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
- currentValue (数组中当前被处理的元素)
- index (当前元素在数组中的索引)
- array (调用 reduce 的数组)
-
initialValue:作为第一次调用 callback 的第一个参数。
const arr = [1,20,-5,3];
//没有初始值:
console.log(arr.reduce((a,b)=>a+b));//19
console.log(arr.reduce((a,b)=>a*b));//-300
//指定初始值:
console.log(arr.reduce((a,b)=>a+b,1));//20
console.log(arr.reduce((a,b)=>a*b,0));//-0
6.2.9 Promise
1)嵌套地狱 案例
案例:用户登录,并展示该用户的各科成绩。在页面发送两次请求:
- 查询用户,查询成功说明可以登录
- 查询用户成功,查询科目
- 根据科目的查询结果,查询成绩
文件名 | 文件描述 | 文件内容 |
---|---|---|
user.json | 用户信息 | {“id”: 1,“name”: “zhangsan”,“password”: “123456”} |
user_corse_1.json | 科目信息 | {“id”: 10,“name”: “chinese”} |
corse_score_10.json | 成绩信息 | {“id”: 100,“score”: 90} |
$.ajax({
url: "mock/user.json",
success(data) {
console.log("查询用户:", data);
$.ajax({
url: `mock/user_corse_${data.id}.json`,
success(data) {
console.log("查询到课程:", data);
$.ajax({
url: `mock/corse_score_${data.id}.json`,
success(data) {
console.log("查询到分数:", data);
},
error(error) {
console.log("出现异常了:" + error);
}
});
},
error(error) {
console.log("出现异常了:" + error);
}
});
},
error(error) {
console.log("出现异常了:" + error);
}
});
2)Promise优化
将 ajax请求 完成后的操作解构出来
new Promise((resolve, reject) => {
$.ajax({
url: "mock/user.json",
success(data) {
console.log("查询用户:", data);
resolve(data.id);
},
error(error) {
console.log("出现异常了:" + error);
}
});
}).then((userId) => {
return new Promise((resolve, reject) => {
$.ajax({
url: `mock/user_corse_${userId}.json`,
success(data) {
console.log("查询到课程:", data);
resolve(data.id);
},
error(error) {
console.log("出现异常了:" + error);
}
});
});
}).then((corseId) => {
console.log(corseId);
$.ajax({
url: `mock/corse_score_${corseId}.json`,
success(data) {
console.log("查询到分数:", data);
},
error(error) {
console.log("出现异常了:" + error);
}
});
});
3)Promise改造
通常在企业开发中,会把 promise 封装成通用方法,如下:封装了一个通用的 get 请求方法
通过比较,我们知道了 Promise 的扁平化设计理念,也领略了这种上层设计
带来的好处
let get = function (url, data) { // 实际开发中会单独放到 common.js 中
return new Promise((resolve, reject) => {
$.ajax({
url: url,
type: "GET",
data: data,
success(result) {
resolve(result);
},
error(error) {
reject(error);
}
});
})
}
// 使用封装的 get 方法,实现查询分数
get("mock/user.json").then((result) => {
console.log("查询用户:", result);
return get(`mock/user_corse_${result.id}.json`);
}).then((result) => {
console.log("查询到课程:", result);
return get(`mock/corse_score_${result.id}.json`)
}).then((result) => {
console.log("查询到分数:", result);
}).catch(() => {
console.log("出现异常了:" + error);
});
6.2.10 模块化
1)介绍
模块化就是把代码进行拆分,方便重复利用。类似 java 中的导包:要使用一个包,必须先导包。而 JS 中没有包的概念,换来的是 模块。
模块功能主要由两个命令构成:export
和import
。
- export命令:用于导出模块的对外接口
- import命令:用于导入其他模块提供的功能
2)export
文件名:main.js
var name = "jack"
var age = 21
const util = {
sum(a,b){
return a + b;
}
}
export {util,name,age};
//简写
export const util = {
sum(a,b){
return a + b;
}
}
//省略名称:注意不允许导出多个default
export default {
sum(a,b){
return a + b;
}
}
3)import
import {util,name, age} from './main'
import a from './main'
6.3 Node.js
前端开发,少不了 node.js;Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
我们关注与 node.js 的 npm 功能就行;
NPM 是随同 NodeJS 一起安装的包管理工具:JavaScript-NPM、Java-Maven;
-
官网下载安装 node.js,并使用 node -v 检查版本
-
配置 npm 使用淘宝镜像
npm config set registry http://registry.npm.taobao.org/
-
大家如果 npm install 安装依赖出现 chromedriver 之类问题,先在项目里运行下面命令
npm install chromedriver --chromedriver_cdnurl=http://cdn.npm.taobao.org/dist/chromedriver
-
然后再运行 npm install
本次项目安装案例
-
下载安装 Node.js:注意教程使用的版本是 10.16.3,下载地址
-
重新安装 npm:注意与 Node.js 对应版本为 6.9.0
-
下载安装 npm
PS F:\software\VsCode\Projects\renren-fast-vue> npm install npm@6.9.0 -g
-
配置npm使用 淘宝镜像
PS F:\software\VsCode\Projects\renren-fast-vue> npm config set registry http://registry.npm.taobao.org/
-
使用npm管理项目**(记录,本次项目无需执行)**
npm init -y
-
-
下载安装 python-2.7.15:下载地址
- 在安装程序中建议选择自动配置环境变量
-
下载安装 visual studio:下载地址
-
打开终端控制台,下载依赖
PS F:\software\VsCode\Projects\renren-fast-vue> npm install
-
运行项目
PS F:\software\VsCode\Projects\renren-fast-vue> npm run dev
https://visualstudio.microsoft.com/zh-hans/downloads/)
6.4 Vue💡
6.4.1 MVM思想
- 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 上。
6.4.2 Vue简介
ue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
官网:https://cn.vuejs.org/
参考:https://cn.vuejs.org/v2/guide/
Git 地址:https://github.com/vuejs
尤雨溪,Vue.js 创作者,Vue Technology 创始人,致力于 Vue 的研究开发。
6.4.3 入门教程
1)安装
官网文档提供了 3 中安装方式:
-
直接 script 引入本地 vue 文件。需要通过官网下载 vue 文件
-
通过 script 引入 CDN 代理。需要联网,生产环境可以使用这种方式
//原型制造、学习 <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script> //生产环境 <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14"></script>
-
通过 npm 安装。这种方式也是官网推荐的方式,需要 nodejs 环境。本课程就采用第三种方式
$ npm install vue
2)创健示例项目
-
新建文件夹 hello-vue,并使用 vscode 打开
-
打开 vscode 控制台 初始化npm项目
项目会生成 package-lock.json 文件,类似于 maven 项目的 pom.xml 文件。
PS C:\Users\ZW L\Desktop\hello-vue> npm init -y
-
给项目安装 vue:项目下会多 node_modules 目录,并且在下面有一个 vue 目录
PS C:\Users\ZW L\Desktop\hello-vue> npm install vue@2.6.10
3)声明式渲染
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 引入vue -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<h2>{{name}}</h2>
</div>
<script>
let vm=new Vue({
el:"#app",
data:{
name: "张三"
}
})
</script>
</body>
</html>
4)双向绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 引入vue -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="name">
<h2>{{name}},你好!</h2>
</div>
<script>
let vm=new Vue({
el:"#app",
data:{
name: "张三"
}
})
</script>
</body>
</html>
6)事件处理
- 这里用
v-on
指令绑定点击事件,而不是普通的onclick
,然后直接操作 num - 普通 click 是无法直接操作 num 的。
- 未来我们会见到更多 v-xxx,这些都是 vue 定义的不同功能的指令。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 引入vue -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<button v-on:click="num++">点赞</button><button v-on:click="cancel">取消</button>
<h2>{{name}},你好!有{{num}}个人为你点赞</h2>
</div>
<script>
let vm=new Vue({
el:"#app",
data:{
name: "张三",
num: 0
},
methods:{
cancel(){
this.num--;
}
}
})
</script>
</body>
</html>
6.4.4 指令💡
6.4.4.1插值表达式
给 HTML 标签内容绑定 Vue示例中定义的数据、表达式
1)花括号
格式:{{表达式}}
- 该表达式 支持 JS 语法,可以调用 js 内置函数(必须有返回值)
- 表达式必须有返回结果。例如 1 + 1,没有结果的表达式不允许使用,如:let a = 1 + 1;
- 可以直接获取 Vue 实例中定义的数据或函数
2)插值闪烁
使用{{}}方式在网速较慢时会出现问题。在数据未加载完成时,页面会显示出原始的{{}}
,加载完毕后才显示正确数据,我们称为插值闪烁。
3)v-text和v-html
可以使用 v-text 和 v-html 指令来替代{{}}。不会出现插值闪烁,当没有数据时,会显示空白或者默认数据。
- v-text:将数据输出到元素内部,不会渲染HTML 代码
- v-html:将数据输出到元素内部,会渲染HTML 代码
<div id="app">
<span v-text="hello"></span> <br />
<span v-html="hello"></span>
</div>
6.4.4.2 v-bind
html 属性不能使用双大括号形式绑定,我们使用 v-bind 指令给 HTML 标签属性绑定值
而且在将 v-bind 用于 class 和 style 时,Vue.js 做了专门的增强
1)绑定class
<div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>
<script>
let vm = new Vue({
el: "#app",
data: {
isActive: true,
hasError: false
}
})
</script>
2)绑定stytle
v-bind:style 的对象语法十分直观,看着非常像 CSS,但其实是一个 JavaScript 对象。style属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,这种方式记得用单引号括起来) 来命名。
例如:font-size–>fontSize
<!-- <div style="color: red; font-size: 30px;"></div> -->
<div id="app" v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
<script>
let vm = new Vue({
el: "#app",
data: {
activeColor: 'red',
fontSize: 30
}
})
</script>
3)绑定其他任意属性
<!-- <div id="app" user="zhangsan"></div> -->
<div id="app" v-bind:user="userName"></div>
<script>
let vm = new Vue({
el: "#app",
data: {
activeColor: 'red',
fontSize: 30,
userName: 'zhangsan'
}
})
</script>
4)缩写
<div id="app" :style="{ color: activeColor, fontSize: fontSize +'px' }" :user="userName">
</div>
6.4.4.3 v-model
v-model 是双向绑定,视图(View)和模型(Model)之间会互相影响。
既然是双向绑定,一定是在视图中可以修改数据,这样就限定了视图的元素类型。目前v-model 的可使用元素有:
- input
- select:单选对应字符串,多选对应也是数组
- textarea:默认对应的 model 是字符串
- checkbox:多个
CheckBox
对应一个 model 时,model 的类型是一个数组,单个 checkbox 值默认是boolean 类型 - radio:对应的值是 input 的 value 值
- components(Vue 中的自定义组件)
基本上除了最后一项,其它都是表单的输入项。
<div id="app">
<input type="checkbox" v-model="language" value="Java" />Java<br />
<input type="checkbox" v-model="language" value="PHP" />PHP<br />
<input type="checkbox" v-model="language" value="Swift" />Swift<br />
<h1>
你选择了:{{language.join(',')}}
</h1>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
let vm = new Vue({
el: "#app",
data: {
language: []
}
})
</script>
6.4.4.4 v-on
1)基本用法
语法: v-on:事件名=“js 片段或函数名”
v-on 指令用于给页面元素绑定事件
事件绑定可以简写,例如v-on:click='add'
可以简写为@click='add'
<div id="app">
<!--事件中直接写 js 片段-->
<button v-on:click="num++">点赞</button>
<!--事件指定一个回调函数,必须是 Vue 实例中定义的函数-->
<button v-on:click="decrement">取消</button>
<h1>有{{num}}个赞</h1>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
let vm = new Vue({
el: "#app",
data: {
num: 100
},
methods: {
decrement() {
this.num--; //要使用 data 中的属性,必须 this.属性名
}
}
})
</script>
2)事件修饰符
在事件处理程序中调用 event.preventDefault()
或 event.stopPropagation()
是非常常见的需求。
尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
为了解决这个问题,Vue.js 为 v-on
提供了事件修饰符。修饰符是由点开头的指令后缀来表示的。
- .stop :阻止事件冒泡到父元素
- .prevent:阻止默认事件发生
- .capture:使用事件捕获模式
- .self:只有元素自身触发事件才执行。(冒泡或捕获的都不执行)
- .once:只执行一次
<div id="app">
<!--右击事件,并阻止默认事件发生-->
<button v-on:contextmenu.prevent="num++">点赞</button>
<br />
<!--右击事件,不阻止默认事件发生-->
<button v-on:contextmenu="decrement($event)">取消</button>
<br />
<h1>有{{num}}个赞</h1>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
let app = new Vue({
el: "#app",
data: {
num: 100
},
methods: {
decrement(ev) {
// ev.preventDefault();
this.num--;
}
}
})
</script>
3)按键修饰符
在监听键盘事件时,我们经常需要检查常见的键值。记住所有的 keyCode
比较困难,所以 Vue 为最常用的按键提供了别名:
- .enter:回车
- .tab:TAB键
- .delete :(捕获“删除”和“退格”键)
- .esc:退出键
- .space:空格
- .up:向上键
- .down:向下键
- .left:向左键
- .right:向右键
Vue 允许为 v-on
在监听键盘事件时添加按键修饰符:
<!-- 只有在 `keyCode` 是 13 时调用 `vm.submit()` -->
<input v-on:keyup.13="submit">
<!-- 同上 -->
<input v-on:keyup.enter="submit">
<!-- 缩写语法 -->
<input @keyup.enter="submit">
4)组合按钮
可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。
- .ctrl
- .alt
- .shift
<!-- Alt + C -->
<input @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
6.4.4.5 v-for
1)遍历数组
语法:v-for=“item in items”
- items:要遍历的数组,需要在 vue 的 data 中定义好。
- item:迭代得到正在遍历的当前元素
<div id="app">
<ul>
<li v-for="user in users">
{{user.name}} - {{user.gender}} - {{user.age}}
</li>
</ul>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
let app = new Vue({
el: "#app",
data: {
users: [
{ name: '柳岩', gender: '女', age: 21 },
{ name: '张三', gender: '男', age: 18 },
{ name: '范冰冰', gender: '女', age: 24 },
{ name: '刘亦菲', gender: '女', age: 18 },
{ name: '古力娜扎', gender: '女', age: 25 }
]
},
})
</script>
2)数组角标
在遍历的过程中,如果我们需要知道数组角标,可以指定第二个参数:
语法:v-for=“(item,index) in items”
- items:要迭代的数组
- item:迭代得到正在遍历的当前元素
- index:迭代到的当前元素索引,从 0 开始。
<div id="app">
<ul>
<li v-for="(user, index) in users">
{{index + 1}}. {{user.name}} - {{user.gender}} - {{user.age}}
</li>
</ul>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
let app = new Vue({
el: "#app",
data: {
users: [
{ name: '柳岩', gender: '女', age: 21 },
{ name: '张三', gender: '男', age: 18 },
{ name: '范冰冰', gender: '女', age: 24 },
{ name: '刘亦菲', gender: '女', age: 18 },
{ name: '古力娜扎', gender: '女', age: 25 }
]
},
})
</script>
3)遍历对象
语法:
- v-for=“value in object”
- v-for=“(value,key) in object”
- v-for=“(value,key,index) in object”
<div id="app">
<ul>
<li v-for="(value, key, index) in user">
{{index + 1}}. {{key}} - {{value}}
</li>
</ul>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
let vm = new Vue({
el: "#app",
data: {
user: { name: '张三', gender: '男', age: 18 }
}
})
</script>
4)Key
用来标识每一个元素的唯一特征,这样 Vue 可以使用“就地复用”策略有效的提高渲染的效率。
最佳实践:
- items 是普通数组:可以使用 index 作为每个元素的唯一标识
- items 是对象数组:可以使用 item.id 作为每个元素的唯一标识
<ul>
<li v-for="(item,index) in items" :key=”index”></li>
</ul>
<ul>
<li v-for="item in items" :key=”item.id”></li>
</ul>
6.4.4.6 v-if和v-show
1)基本用法
语法:v-if=“布尔表达式”, v-show=“布尔表达式”
- v-if:顾名思义,条件判断。当得到结果为 true 时,所在的元素才会被渲染。
- v-show:当得到结果为 true 时,所在的元素才会被显示。否则被隐藏(dispaly:none)
<div id="app">
<button v-on:click="show = !show">点我呀</button>
<br>
<h1 v-if="show">
看到我啦?!
</h1>
<h1 v-show="show">
看到我啦?!show
</h1>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
let app = new Vue({
el: "#app",
data: {
show: false
}
})
</script>
2)于v-for结合
当 v-if 和 v-for 出现在一起时,v-for 优先级更高。也就是说,会先遍历,再判断条件。
<div id="app">
<ul>
<li v-for="(user, index) in users" v-if="user.gender == '女'">
{{index + 1}}. {{user.name}} - {{user.gender}} - {{user.age}}
</li>
</ul>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
let app = new Vue({
el: "#app",
data: {
users: [
{ name: '柳岩', gender: '女', age: 21 },
{ name: '张三', gender: '男', age: 18 },
{ name: '范冰冰', gender: '女', age: 24 },
{ name: '刘亦菲', gender: '女', age: 18 },
{ name: '古力娜扎', gender: '女', age: 25 }
]
},
})
</script>
6.4.4.7 v-else和v-else-if
v-else 元素必须紧跟在带 v-if
或者 v-else-if
的元素的后面,否则它将不会被识别
<div id="app">
<button v-on:click="random=Math.random()">点我呀
</button><span>{{random}}</span>
<h1 v-if="random >= 0.75">
看到我啦?!v-if >= 0.75
</h1>
<h1 v-else-if="random > 0.5">
看到我啦?!v-else-if > 0.5
</h1>
<h1 v-else-if="random > 0.25">
看到我啦?!v-else-if > 0.25
</h1>
<h1 v-else>
看到我啦?!v-else
</h1>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
let app = new Vue({
el: "#app",
data: {
random: 1
}
})
</script>
6.4.5 其他属性💡
6.4.5.1 计算属性(computed)
某些结果是基于之前数据实时计算出来的,我们可以利用计算属性来完成
<div id="app">
<ul>
<li>西游记:价格{{xyjPrice}},数量:
<input type="number" v-model="xyjNum">
</li>
<li>水浒传:价格{{shzPrice}},数量:
<input type="number" v-model="shzNum">
</li>
<li>总价:{{totalPrice}}</li>
</ul>
</div>
<script type="text/javascript">
let app = new Vue({
el: "#app",
data: {
xyjPrice: 56.73,
shzPrice: 47.98,
xyjNum: 1,
shzNum: 1
},
computed: {
totalPrice() {
return this.xyjPrice * this.xyjNum + this.shzPrice * this.shzNum;
}
},
})
</script>
6.4.5.2 监听(watch)
watch 可以让我们监控一个值的变化,从而做出相应的反应。
<div id="app">
<ul>
<li>西游记:价格{{xyjPrice}},数量:
<input type="number" v-model="xyjNum">
</li>
<li>水浒传:价格{{shzPrice}},数量:
<input type="number" v-model="shzNum">
</li>
<li>总价:{{totalPrice}}</li>
{{msg}}
</ul>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
let app = new Vue({
el: "#app",
data: {
xyjPrice: 56.73,
shzPrice: 47.98,
xyjNum: 1,
shzNum: 1,
msg: ""
},
computed: {
totalPrice() {
return this.xyjPrice * this.xyjNum + this.shzPrice * this.shzNum;
}
},
watch: {
xyjNum(newVal, oldVal) {
if (newVal >= 3) {
this.msg = "西游记没有更多库存了";
this.xyjNum = 3;
} else {
this.msg = "";
}
}
}
})
</script>
6.4.5.3 过滤器(filters)
过滤器不改变真正的data
,而只是改变渲染的结果,并返回过滤后的版本。在很多不同的情况下,过滤器都是有用的,比如尽可能保持 API 响应的干净,并在前端处理数据的格式。
过滤器常用来处理文本格式化的操作。过滤器可以用在两个地方:双花括号插值
和 v-bind 表达式
1)局部过滤器
注册在当前 vue 实例中,只有当前实例能用
示例:展示用户列表性别显示男女
<div id="app">
<table>
<tr v-for="user in userList">
<td>{{user.id}}</td>
<td>{{user.name}}</td>
<!-- 使用代码块实现,有代码侵入 -->
<td>{{user.gender===1? "男":"女"}}</td>
<td>{{user.gender | genderFilter}}</td>
</tr>
</table>
</div>
<script>
let app = new Vue({
el: "#app",
data: {
userList: [
{ id: 1, name: 'jacky', gender: 1 },
{ id: 2, name: 'peter', gender: 0 }
]
},
// filters 定义局部过滤器,只可以在当前 vue 实例中使用
filters: {
genderFilter(gender) {
return gender === 1 ? '男~' : '女~'
}
}
});
</script>
2)全局过滤器
任何 vue 实例都可以使用
示例:名字转换为大写
<div id="app">
<table>
<tr v-for="user in userList">
<td>{{user.id}}</td>
<!-- 任何 vue 实例都可以使用 -->
<td>{{user.name | capitalize}}</td>
<!-- 使用代码块实现,有代码侵入 -->
<td>{{user.gender===1? "男":"女"}}</td>
<td>{{user.gender | genderFilter}}</td>
</tr>
</table>
</div>
<script>
Vue.filter('capitalize', function (value) {
return value.charAt(0).toUpperCase() + value.slice(1)
})
let app = new Vue({
el: "#app",
data: {
userList: [
{ id: 1, name: 'jacky', gender: 1 },
{ id: 2, name: 'peter', gender: 0 }
]
},
// filters 定义局部过滤器,只可以在当前 vue 实例中使用
filters: {
genderFilter(gender) {
return gender === 1 ? '男~' : '女~'
}
}
});
</script>
6.4.6 组件化💡
在大型应用开发的时候,页面可以划分成很多部分。往往不同的页面,也会有相同的部分。例如可能会有相同的头部导航。
但是如果每个页面都独自开发,这无疑增加了我们开发的成本。所以我们会把页面的不同部分拆分成独立的组件,然后在不同页面就可以共享这些组件,避免重复开发。
在 vue 里,所有的 vue 实例都是组件。
- 组件其实也是一个 Vue 实例,因此它在定义时也会接收:data、methods、生命周期函数等
- 不同的是组件不会与页面的元素绑定,否则就无法复用了,因此没有 el 属性。
- 但是组件渲染需要 html 模板,所以增加了 template 属性,值就是 HTML 模板
- 全局组件定义完毕,任何 vue 实例都可以直接在 HTML 中通过组件名称来使用组件了
- data 必须是一个函数,不再是一个对象:官网说明
1)全局组件
通过 Vue 的 component 方法来定义一个全局组件
<div id="app">
<!--使用定义好的全局组件-->
<counter></counter>
<counter></counter>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
// 定义全局组件,两个参数:1,组件名称。2,组件参数
Vue.component("counter", {
template: '<button v-on:click="count++">你点了我 {{ count }} 次,我记住了.</button > ',
data() {
return {
count: 0
}
},
})
let app = new Vue({
el: "#app"
})
</script>
2)局部组件
一旦全局注册,就意味着即便以后你不再使用这个组件,它依然会随着 Vue 的加载而加载。因此,对于一些并不频繁使用的组件,我们会采用局部注册。
这个 counter 组件只能在当前的 Vue 实例中使用。
components 就是当前 vue 对象子组件集合。以 key : value 形式声明
- key :定义子组件的名称
- value:组件对象
<div id="app">
<!--使用定义好的全局组件-->
<counter></counter>
<counter></counter>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
// 定义局部组件
const counter = {
template: '<button v-on:click="count++">你点了我 {{ count }} 次,我记住了.</button > ',
data() {
return {
count: 0
}
}
};
let app = new Vue({
el: "#app",
components: {
//counter: counter 将定义的对象注册为组件
counter // 简写
}
})
</script>
6.4.7 生命周期钩子函数
1)生命周期
每个 Vue 实例在被创建时都要经过一系列的初始化过程 :创建实例,装载模板,渲染模板等等。Vue 为生命周期中的每个状态都设置了钩子函数(监听函数)。每当 Vue 实例处于不同的生命周期时,对应的函数就会被触发调用。
生命周期:你不需要立马弄明白所有的东西。
2)钩子函数
- beforeCreated:我们在用 Vue 时都要进行实例化,因此,该函数就是在 Vue 实例化时调用,也可以将他理解为初始化函数比较方便一点,在 Vue1.0 时,这个函数的名字就是init。
- created:在创建实例之后进行调用。
- beforeMount:页面加载完成,没有渲染。如:此时页面还是{{name}}
- mounted:我们可以将他理解为原生 js 中的 window.οnlοad=function({.,.}),或许大家也在用 jquery,所以也可以理解为 jquery 中的$(document).ready(function(){…}),他的功能就是 : 在 dom 文 档 渲 染 完 毕 之 后将 要 执 行 的 函 数 , 该 函 数 在 Vue1.0 版 本 中 名 字 为compiled。 此时页面中的{{name}}已被渲染成张三
- beforeDestroy:该函数将在销毁实例前进行调用 。
- destroyed:改函数将在销毁实例时进行调用。
- beforeUpdate:组件更新之前。
- updated:组件更新之后。
<div id="app">
<span id="num">{{num}}</span>
<button v-on:click="num++">赞!</button>
<h2>
{{name}},非常帅!!!有{{num}}个人点赞。
</h2>
</div>
<script>
let app = new Vue({
el: "#app",
data: {
name: "张三",
num: 100
},
methods: {
show() {
return this.name;
},
add() {
this.num++;
}
},
beforeCreate() {
console.log("=========beforeCreate=============");
console.log("数据模型未加载:" + this.name, this.num);
console.log("方法未加载:" + this.show());
console.log("html 模板未加载:" + document.getElementById("num"));
},
created: function () {
console.log("=========created=============");
console.log("数据模型已加载:" + this.name, this.num);
console.log("方法已加载:" + this.show());
console.log("html 模板已加载:" + document.getElementById("num"));
console.log("html 模板未渲染:" + document.getElementById("num").innerText);
},
beforeMount() {
console.log("=========beforeMount=============");
console.log("html 模板未渲染:" + document.getElementById("num").innerText);
},
mounted() {
console.log("=========mounted=============");
console.log("html 模板已渲染:" + document.getElementById("num").innerText);
},
beforeUpdate() {
console.log("=========beforeUpdate=============");
console.log("数据模型已更新:" + this.num);
console.log("html 模板未更新:" + document.getElementById("num").innerText);
},
updated() {
console.log("=========updated=============");
console.log("数据模型已更新:" + this.num);
console.log("html 模板已更新:" + document.getElementById("num").innerText);
}
});
</script>
6.4.8 模块化开发💡
1)入门案例
-
全局安装 webpack
PS C:\Users\ZW L> npm install webpack@4.41.2 -g
-
全局安装 vue 脚手架
PS C:\Users\ZW L> npm install -g @vue/cli@4.0.3 PS C:\Users\ZW L> npm install -g @vue/cli-init
-
初始化 vue 项目
#vue 脚手架使用 webpack 模板初始化一个项目 PS C:\Users\ZW L\Desktop> vue init webpack vue-hello
-
启动 vue 项目
项目的 package.json 中有 scripts,代表我们能运行的命令
启动项目:npm start = npm run dev
将项目打包:npm run build
PS C:\Users\ZW L\Desktop\vue-hello> npm run dev
2)项目结构💡
目录/文件 | 说明 |
---|---|
build | 项目构建(webpack)相关代码 |
config | 项目配置目录:包括项目IP、端口号,静态资源目录、访问路径、是否自动打开浏览器等。我们初学可以使用默认的。 |
node modules | npm加载的项目依赖模块 |
src | 这里是我们要开发的目录,基本上要做的事情都在这个目录里。里面包含了几个目录及文件: ● assets:放置一些图片,如logo等。 ● components:目录里面放了一个组件文件,可以不用 ● App.vue:项目入口文件,我们也可以直接将组件写这里,而不使用components目录。 ● main.js:项目的核心文件。 |
static | 静态资源目录,如图片、字体等。 |
test | 初始测试目录,可删除 |
.xxx文件 | 其他配置文件:语法配置,gt配置等 |
index.html | 首页入口文件,你可以添加一些meta信息或统计代码啥的。 |
package.json | 项目信息:项目名称、版本、描述、作者,scripts(代表我们能运行的命令),依赖列表,engines(node、npm版本信息)等 |
package-lock.json | 依赖下载的详细说明。包括版本、下载地址等 |
README.md | 项目的说明文档,markdown格式 |
3)单文件组件
Vue 单文件组件模板有三个部分;
<!-- 编写模板 -->
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
</template>
<!-- vue 实例配置 -->
<script>
export default {
name: "HelloWorld",
data() {
return {
msg: "Welcome to Your Vue.js App",
};
},
};
</script>
<!-- 样式 -->
<!-- scoped 限制该样式只被当前组件使用 -->
<style scoped>
h1,
h2 {
font-weight: normal;
}
</style>
4)配置用户代码片段💡
Visual Studio Code —> 文件 —> 首选项 —> 配置用户 —> 代码片段
{
"vue": {
"prefix": "vue",
"body": [
"<template>",
" <div class=''></div>",
"</template>",
"",
"<script>",
"// 这里可以导入其他文件(比如:组件,工具 js,第三方插件 js,json文件,图片文件等等)",
"// 例如:import 《组件名称》 from '《组件路径》';",
"",
"export default {",
" // import 引入的组件需要注入到对象中才能使用",
" components: {},",
" props: {},",
" data () {",
" return {",
"",
" }",
" },",
" computed: {},",
" watch: {},",
" methods: {",
"",
" },",
" // 生命周期 - 创建完成(可以访问当前 this 实例)",
" created () {",
"",
" },",
" // 生命周期 - 挂载完成(可以访问 DOM 元素)",
" mounted () {",
"",
" },",
" beforeCreate () {},",
" beforeMount () {},",
" beforeUpdate () {},",
" updated () {},",
" beforeDestroy () {},",
" destroyed () {},",
" activated () {}",
"}",
"</script>",
"",
"<style lang='scss' scoped>",
" // @import url($3); 引入公共 css 类",
" $4",
"</style>"
],
"description": "生成 vue 模板"
}
}
5)整合 Element UI💡
-
安装 Element UI
PS C:\Users\ZW L\Desktop\vue-hello> npm i element-ui
-
在 main.js 中 引入
import Vue from 'vue' import App from './App' import router from './router' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(ElementUI) Vue.config.productionTip = false new Vue({ el: '#app', router, components: { App }, template: '<App/>' })
-
将 App.vue 改为 element-ui 中的后台布局
-
添加测试路由、组件,测试跳转逻辑
6.5 Babel
Babel 是一个 JavaScript 编译器,我们可以使用 es 的最新语法编程,而不用担心浏览器兼容问题。他会自动转化为浏览器兼容的代码
6.6 Webpack
自动化项目构建工具。gulp 也是同类产品