前端工程师“Front-End-Developer”源自于美国。大约从2005年开始正式的前端工程师角色被行业所认可,到了2010年,互联网开始全面进入移动时代,前端开发的工作越来越重要。
最初所有的开发工作都是由后端工程师完成的,随着业务越来越繁杂,工作量变大,于是我们将项目中的可视化部分和一部分交互功能的开发工作剥离出来,形成了前端开发。
nodejs安装
vscode 安装
vscode 常用插件安装
Chinese , Live Server , Vetur , Vue-helper , Auto close tag ,Auto Rename Tag ,HTML CSS Support ,JavaScript(ES6) …
vscode本身没有新建项目的选项,所以要先创建一个空的文件夹,如project_xxxx。
然后打开vscode,再在vscode里面选择 File -> Open Folder 打开文件夹,这样才可以创建项目。
打开文件夹后,选择 “文件 -> 将工作区另存为…”,为工作区文件起一个名字,存储在刚才的文件夹下即可
然后 可以在工作区下 创建前端工程的文件
ECMAScript 6.0(简称 ES6)是 JavaScript 语言的下一代标准, 2015 年 6 月正式发布。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
一个常见的问题是,ECMAScript 和 JavaScript 到底是什么关系?
要讲清楚这个问题,需要回顾历史。1996 年 11 月,JavaScript 的创造者 Netscape 公司,决定将 JavaScript 提交给标准化组织 ECMA,希望这种语言能够成为国际标准。次年,ECMA 发布 262 号标准文件(ECMA-262)的第一版,规定了浏览器脚本语言的标准,并将这种语言称为 ECMAScript,这个版本就是 1.0 版。
因此,ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现(另外的 ECMAScript 方言还有 Jscript 和 ActionScript)
ES6相对之前的版本语法更严格,新增了面向对象的很多特性以及一些高级特性。本部分只学习项目开发中涉及到ES6的最少必要知识,方便项目开发中对代码的理解。
// var 声明的变量没有局部作用域
// let 声明的变量 有局部作用域
{
var a = 1;
let b = 2;
}
console.log(a)
console.log(b) //b is not defined
// var 可以声明多次
// let 只能声明一次
var m = 1;
var m = 2;
let n = 10;
let n = 20; //'n' has already been declared
console.log(m)
console.log(n)
// 1、声明之后不允许改变
const PI = "3.1415926"
PI = 3 // TypeError: Assignment to constant variable.
// 2、一但声明必须初始化,否则会报错
const MY_AGE // Missing initializer in const declaration
创建 03-解构赋值-数组解构.js
解构赋值是对赋值运算符的扩展。
他是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。
在代码书写上简洁且易读,语义更加清晰明了;也方便了复杂对象中数据字段获取。
//1、数组解构
let a = 1, b = 2, c = 3
//console.log(a, b, c)
// ES6
let [x, y, z] = [1, 2, 3]
//console.log(x, y, z)
//2、对象解构
let user = {name: 'Helen', age: 18}
// 传统
let name1 = user.name
let age1 = user.age
console.log(name1, age1)
// ES6
let { name, age } = user //注意:结构的变量必须是user中的属性
console.log(name, age)
模板字符串相当于加强版的字符串,用反引号 `,除了作为普通字符串,还可以用来定义多行字符串,还可以在字符串中加入变量和表达式。
<script>
// 1、模板字符串的语法
// 没用模板字符串之前 想要在字符串中加入变量可以这样写:
let name ="zs";
let age = 18;
let str = "My name is "+name+
",I am "+age+" years old";
console.log(str);
// 使用模板字符串之后 想要在字符串中加入变量可以这样写:
let str1 = `My name is ${name}
,I am ${age}`;
console.log(str1);
// 模板字符串中 使用函数
function getName(){
return "张三";
}
let str2 = `My name is ${getName()}`
console.log(str2);
</script>
//传统方式定义对象
const name = "lucy"
const age = 20
const user1 = {name:name,age:age}
//console.log(user1)
//es6
const user2 = {name,age}
console.log(user2)
拓展运算符(…)用于取出参数对象所有可遍历属性然后拷贝到当前对象。
//对象复制
let person1 = {name: "Amy", age: 15}
let someone1 = { ...person1}
//console.log(someone1)
//对象合并
let age = {age: 15}
let name = {name: "Amy"}
let person2 = {...age, ...name}
console.log(person2)
箭头函数提供了一种更加简洁的函数书写方式。基本语法是:
参数 => 函数体
箭头函数多用于匿名函数的定义
//传统方式定义函数
var f1 = function(a) {
return a
}
//console.log(f1(3))
//es6使用箭头函数定义
//参数 => 函数体
var f2 = a => a
//console.log(f2(4))
使用箭头函数
// 当箭头函数没有参数或者有多个参数,要用 () 括起来。
// 当箭头函数函数体有多行语句,用 {} 包裹起来,表示代码块,
// 当只有一行语句,并且需要返回结果时,可以省略 {} , 结果会自动返回。
var f3 = function(m,n) {
return m+n
}
//es6
var f4 = (m,n) => m+n
console.log(f4(4,5))
<script>
//不定参数
function fun(name,...hobby){
console.log(`${name}的兴趣爱好是${hobby}`);
}
fun("张三","打球","跳舞","唱歌");
//给函数的参数设置默认值
//之前的写法
function add1(a,b){
// 判断b是否有值
b = b || 1; // 如果b没有值,那么就设置b的值为1
return a+b;
}
//es6的写法
function add2(a,b = 1){
return a+b;
}
console.log(add2(1,10));
</script>
map 和 reduce
<p>
数组中新增的map和reduce方法
</p>
<script>
//map方法 接受一个函数参数 ,对数组中的所有元素 使用这个函数加工处理,然后返回一个新的数组
let arr = [1,2,3,4,5,6,7,8,9,10];
let newarr = arr.map((x)=>{return x*2});
console.log(newarr);
// reduce 方法 语法:
// arr.reduce(callback,[initialValue])
// reduce 为数组中的每一个元素 依次执行回调函数,不包括数组中未被赋值的元素
// callback 回调函数 有四个参数:
// 1. previousValue 上一次执行回调函数的返回值 或者 提供的初始值
// 2. currentValue 数组中当前被处理的元素
// 3. currentIndex 当前元素在数组中的索引
// 4. array 当前处理的数组 也就是调用 reduce 的数组
// initialValue 初始值 (作为 第一次调用callback 的第一个参数)
let arr2 = [1,2,3,4,5,6,7,8,9,10];
let result = arr2.reduce((a,b)=>a+b,10);
let result2 = arr2.reduce((a,b)=>a*b,0);
console.log(result2);
</script>
<!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>
<script src="/js/jquery-3.4.1.min.js"></script>
</head>
<body>
<script>
//1.查询用户的信息
//2.根据用户的id查询他得课程
//3.根据课程id查询他得分数
// $.ajax({
// url:"/mock/user.json",
// success:function(res){
// console.log("用户信息"+res);
// //根据用户信息查询课程信息
// $.ajax({
// url:`/mock/course_${res.id}.json`,
// success:function(res){
// console.log("课程信息"+res);
// //根据课程信息查询分数
// $.ajax({
// url:`/mock/score_${res.id}.json`,
// success:function(res){
// console.log("分数信息"+res.score);
// },
// error(error){
// console.log("查询分数信息"+error);
// }
// })
// },
// error(error){
// console.log("查询课程信息"+error);
// }
// })
// },
// error(error){
// console.log("查询用户错误"+error);
// }
// })
//上面的写法 很繁琐 ,下面的写法更简洁
// 借助 Promise 实现 Promise 可以封装异步操作
// let p = new Promise((resolve, reject) => {
// $.ajax({
// url: "/mock/user.json",
// success: function (res) {
// console.log("用户信息" + res);
// resolve(res); // 表式 把结果向下传递
// },
// error(error) {
// reject(error);
// }
// })
// });
// 下面这个 res 是上面查询的 用户信息
// p.then(res => {
// return new Promise((resolve, reject) => {
// $.ajax({
// url: `/mock/course_${res.id}.json`,
// success: function (res) {
// console.log("课程信息" + res);
// resolve(res); // 表式把结果向下传递
// }
// })
// .then(res => {
// console.log("上一步查询的课程信息" + res);
// $.ajax({
// url: `/mock/score_${res.id}.json`,
// success: function (res) {
// console.log("查询到的成绩" + res.score)
// }
// })
// })
// })
// }
// )
// 实际开发中的写法: 会把promise 封装成 通用的方法
function getMsg(url,data){
return new Promise((resolve,reject)=>{
$.ajax({
url,
data,
success(res){
resolve(res);
},
error(error){
reject(error);
}
})
})
}
getMsg("/mock/user.json")
.then(res=>{
console.log("用户信息"+res);
//根据用户的id查询课程
return getMsg(`/mock/course_${res.id}.json`);
}
)
.then(res=>{
console.log("课程信息"+res);
//根据课程id查询分数
return getMsg(`/mock/score_${res.id}.json`);
}
)
.then(res=>{
console.log("分数信息"+res.score);
}
)
</script>
</body>
</html>
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
使用idea 创建web 工程 安装vue.js 插件 , 创建html 页面 引入 vue.js 查看有没有提示
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<div id="app"> // mvvm 中的 第一个 v
{{message}}
<input type="text" v-model="message" >
div>
var app = new Vue({ // 创建 vue 实例 即 mvvm 中的 vm
el: '#app', // 接管 app 这个 dom
data: { // mvvm 中的 第一个 m
message: 'Hello Vue!'
}
})
说明:
这里有几点重要说明:
new Vue 我们创建了Vue对象;
el 指定了绑定DOM,接管DOM操作;
data:初始化数据,页面可以直接访问;
v-model 重点 可以实现数据双向绑定,改变了这里的值,其他地方也根据改变;
{{xxxxx}} 显示数据;
核心原理:mvvm
这里 核心就是 ViewModel 里面有DOM监听以及数据绑定,View是页面数据展示 Model也就是前面data里定义的,通过Vue来实现各种快捷功能,我们用普通js写的话 得写一大串Js代码;
mvvm设计模式 这里的
第一m是 model 也就是vm的data属性
第二个v是 view 视图 网页模版
最后vm就是中间vue的 viewmodel 代码体现就是vm对象或者vm实例;
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
head>
<body>
<div id="app">
<h2>插值h2>
<input type="text" v-model="msg">
<span v-once>Message: {{ msg }}span>
<p>{{message}}p>
<p><span v-html="message">span>p>
<h2>数据绑定-- 双大括号语法不能作用在 html 的属性上面 遇到这种情况应该使用 v-bind 指令h2>
<div class="c">div1div>
<div v-bind:class="c">div2div> <%--v-bind 把 vue 实例的 c 属性值 赋值给 这个div 标签的class 属性--%>
<div v-bind:id="dynamicId">1div>
<div :class="c">1div> <%--简写 v-bind: --%>
<button :disabled="isDisabled">Buttonbutton>
<a v-bind:href="url">百度a>
<a :href="url">百度2a>
<h2>js表达式h2>
<p>{{number+1}}p>
<p>{{ ok ? 'YES' : 'NO' }}p>
<p>{{ message2.split(' ').reverse().join(',') }}p>
<p v-if="see">看得到吗?p>
<h2>事件绑定h2>
<button v-on:click="doSomething">按钮button>
<button @click="doSomething">按钮2button>
<h2>总结h2>
<pre>
指令: 指令 (Directives) 是带有 v- 前缀的特殊 attribute。
指令 attribute 的值预期是单个 JavaScript 表达式 (v-for 是例外情况,稍后我们再讨论)。
指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。
指令:
v-model="vuedata" 数据双向绑定
v-bind:htmlattr="vuedata" 属性动态赋值
v-bind的简写 :htmlattr="vuedata"
v-on:htmlevent="vuemethods" 事件动态绑定
v-on的简写 @htmlevent = "vuemethods"
v-html : 可以解析 html 标签
v-once : 一次性的插值
v-if="vuedata" v-if 指令将根据表达式 vuedata 的值的真假来插入/移除 x 元素。
pre>
div>
<script type="text/javascript">
var app = new Vue({
el: '#app', // 接管 app 这个 dom
data: {
msg: 'Hello Vue!',
message:'hello',
c:'c',
dynamicId:'5',
isDisabled:false,
url:"https://www.baidu.com",
number:2,
ok:true,
message2:"ni hao ma",
see:false
},
methods:{
doSomething(){
alert("点我干嘛");
}
}
})
//app.ok = false;
script>
<style type="text/css">
.c{
border: 1px solid black;
}
.c2{
border: 1px solid red;
}
style>
body>
html>
<html>
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
head>
<body>
<div id="app">
<a v-bind:[attributename]="msg"> 超链接 a>
<a href="#" v-on:[eventName]="doSomething"> 超链接2 a>
div>
<script type="text/javascript">
new Vue({
el:'#app',
data:{
attributename:'href',
msg:'1mubanyufa.html',
eventname:'click'
},
methods:{
doSomething(){
alert("点我干嘛")
}
}
})
script>
body>
html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>-->
<script src="js/vue.js" type="text/javascript"></script>
</head>
<body>
<div id="app">
<h2>v-if</h2>
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no </h1>
<h2>v-if in template</h2>
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
<h2>v-else</h2>
<div v-if="Math.random() > 0.5">
Now you see me
</div>
<div v-else>
Now you don't
</div>
<h2>v-else-if</h2>
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
<H2>用 key 管理可复用的元素</H2>
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>
<BUTTON @click="toggle">toggle</BUTTON>
<h2>v-show</h2>
<h1 v-show="ok">Hello! v-show</h1>
<h2>不推荐同时使用 v-if 和 v-for。请查阅风格指南以获取更多信息。</h2>
</div>
<h2>总结</h2>
<pre>
v-if 用于条件性的渲染一块内容
在template 上使用 v-if 条件渲染分组 最终的渲染结果是不包含template
v-else 表示 v-if 的else 块
v-else-f 表示 v-if 的 else -if 可以连续使用 多分枝
用key 管理 服用的元素
v-show 只是简单的切换元素的 display
</pre>
<script type="text/javascript">
new Vue({
el:"#app",
data:{
awesome:false,
ok:false,
type:'B',
loginType:'username'
},
methods:{
toggle(){
this.loginType= this.loginType=='username'?'email':'username'
}
}
});
</script>
</body>
</html>
<html>
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
head>
<body>
<div id="app">
<h2>用 v-for 把一个数组对应为一组元素h2>
<p>我们可以用 v-for 指令基于一个数组来渲染一个列表。v-for 指令需要使用 item in items 形式的特殊语法,
其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名p>
<ul>
<li v-for="item in items">{{item.date}}li>
ul>
<h2> 在 v-for 块中,我们可以访问所有父作用域的属性。v-for 还支持一个可选的第二个参数,即当前项的索引。 可以不看h2>
<ul>
<li v-for="(item,index) in items" v-bind:key="index" v-bind:title="item.id">
{{parentMessage}}--{{item.date}}--{{index}}
li>
ul>
<ul>
<li v-for="(item,index) in myitems2.items2" v-bind:key="item.id" >
{{parentMessage}}--{{item.date}}--{{index}}
li>
ul>
<h2>在 v-for 里使用对象h2>
<ul>
<li v-for="(value,name,index) in student">
{{name}}--{{value}}--{{index}}
li>
ul>
<pre>
注意
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性:
<div v-for="item in items" v-bind:key="item.id">
</div>
建议尽可能在使用 v-for 时提供 key attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
不要使用对象或数组之类的非基本类型值作为 v-for 的 key。请用字符串或数值类型的值。
pre>
<hr>
<table style="border: 1px solid black">
<tr>
<th>姓名th>
<th>年龄th>
<th>联系方式th>
tr>
<tr v-for="(stu,index) in students" v-bind:key="index">
<td>{{stu.name}}td>
<td>{{stu.age}}td>
<td>{{stu.phone}}td>
tr>
table>
div>
<script type="text/javascript">
var vue = new Vue({
el:"#app",
data:{
parentMessage: 'Parent',
items:[
{
date:"星期1",
id:1
},
{
date:"星期2",
id:2
},
{
date:"星期3",
id:3
}
],
myitems2:{
parentMessage2:'Parent2',
items2:[
{
date:"星期1111"
},
{
date:"星期2222"
},
{
date:"星期3333"
}
]
},
student:{
name:'zs',
age:18,
phone:'136'
},
students:[
{
name:'zs',
age:18,
phone:'111'
},
{
name:'ls',
age:18,
phone:'222'
},{
name:'ww',
age:18,
phone:'333'
}
]
}
});
vue.students.push({name:'zl',age:19,phone:'444'})
script>
body>
html>
<html>
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
head>
<body>
<div id="app">
<h2>
计算属性
h2>
<pre>
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如:
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示变量 message 的翻转字符串。
当你想要在模板中多次引用此处的翻转字符串时,就会更加难以处理。
所以,对于任何复杂逻辑,你都应当使用计算属性。
vue computed 属性 用于计算复杂业务逻辑 把复杂业务逻辑抽取 实现维护方便
pre>
div>
<hr>
<p>例子p>
<div id="example">
<p>Original message: "{{ message }}"p>
<p>Computed reversed message: "{{ reversedMessage }}"p>
<button @click="change()">changebutton>
<h2>计算属性 setterh2>
<p>Computed reversed info: "{{ reversedInfo }}"p>
<button @click="change2()">change2button>
<h2>计算属性缓存 vs 方法h2>
<p>Original message: "{{ message }}"p>
<p>Computed reversed message: "{{ reversedMessage }}"p>
<p>Computed reversed message: "{{ reversedMessage }}"p>
<p>Computed reversed message: "{{ reversedMessage2() }}"p>
<p>Computed reversed message: "{{ reversedMessage2() }}"p>
div>
<script type="text/javascript">
var count = 1;
new Vue({
el: '#example',
data:{
message:'Hello',
info:'Hello2'
},
computed:{
// 计算属性的 getter
reversedMessage() {
// `this` 指向 vm 实例
count++;
console.log('---调用了message get');
console.log(count);
return this.message.split('').reverse().join('')
},
reversedInfo:{
get(){
console.log('调用了info get')
return this.info.split('').reverse().join('')
},
set(newValue){
console.log('调用了info set');
console.log(newValue);
this.info = newValue;
}
}
},
methods:{
change(){
this.message="springcloud"
},
change2(){
this.reversedInfo="springboot"
},
reversedMessage2 () {
count++;
console.log('---222');
console.log(count);
return this.message.split('').reverse().join('')
}
}
});
script>
body>
html>
Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。当你有一些数据需要随着其它数据变动而变动时,你很容易滥用
watch
——特别是如果你之前使用过 AngularJS。然而,通常更好的做法是使用计算属性而不是命令式的watch
回调
<html>
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
head>
<body>
<div id="app">
<input type="text" v-model="n"> 的平方是:{{result}} {{result2()}}
div>
<div id="app2">
<input type="text" v-model="n2"> 的平方是:{{result2}}
div>
<script type="text/javascript">
new Vue({
el:"#app",
data:{
n:1,
// result:1
},
computed:{ // 计算属性
result(){
return this.n * this.n;
}
},
methods:{
result2(){
return this.n*this.n;
}
}
});
let vm = new Vue({
el:"#app2",
data:{
n2:1,
result2:1
},
watch:{
n2(newN,oldN){
console.log(newN,oldN);
this.result2= newN*newN;
}
}
});
//也会有下面的写法
//vm.$watch('n2',function(newN,oldN){
// console.log(newN,oldN);
// this.result2= newN*newN;
//})
script>
body>
html>
3.7class与style绑定
<html>
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
head>
<body>
<pre>
操作元素的 class 列表和内联样式是数据绑定的一个常见需求。因为它们都是属性,
所以我们可以用 v-bind 处理它们:只需要通过表达式计算出字符串结果即可。
不过,字符串拼接麻烦且易错。因此,在将 v-bind 用于 class 和 style 时,Vue.js 做了专门的增强。
表达式结果的类型除了字符串之外,还可以是对象或数组。
pre>
<h2>绑定 HTML Classh2>
<div id="app">
<h3>对象语法h3>
<div :class="{ active: isActive }">div>
<hr>
<div class="static"
:class="{ active: isActive, 'text-danger': hasError }"
>123div>
<hr>
<div :class="classObject"
>123div>
<hr>
<h2>数组语法h2>
<div v-bind:class="[activeClass, errorClass]">div>
<h2>绑定内联样式 v-bind:styleh2>
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">123div>
<div v-bind:style="styleObject">222div>
div>
<script type="text/javascript">
new Vue({
el:"#app",
data:{
isActive:true,
hasError: true,
classObject:{
active: true,
'text-danger': false
},
activeClass: 'active',
errorClass: 'text-danger',
activeColor: 'red',
fontSize: 30,
styleObject: {
color: 'red',
fontSize: '13px'
}
}
});
script>
<style type="text/css">
.active{
border: 1px solid black;
width: 100px;
height: 100px;
}
.static{
background-color: aquamarine;
}
.text-danger{
color: red;
}
style>
body>
html>
<html>
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
head>
<body>
<h2>可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。h2>
<div id="app">
<button @click="counter+=1">Add 1button>
<p>The button above has been clicked {{ counter }} times.p>
div>
<hr>
<h2>事件处理方法h2>
<div id="example-2">
<button @click="greet">Greetbutton>
div>
<h2>内联处理器中的方法h2>
<div id="example-3">
<button @click="say('hi')">Say hibutton>
<p>有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event 把它传入方法:p>
<a @click="warn('Form cannot be submitted yet.', $event)" href="https://www.baidu.com">
Submit
a>
div>
<h2>事件修饰符h2>
<pre>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。
尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。
.stop
.prevent
.capture
.self
.once
.passive
pre>
<div id="example-4">
<a @click.prevent="doThis" href="https://www.baidu.com">
百度
a>
<hr>
<div @click = "doDivClick" style="width: 100px;height: 100px;border: 1px solid black">
<a @click.stop="doThis" href="https://www.baidu.com">
百度
a>
div>
div>
<h2>按键修饰符h2>
<div id="example-5">
<input type="text" v-model="name" @keyup.enter="submit">
div>
<script type="text/javascript">
new Vue({
el:"#app",
data:{
counter:0
}
});
var vue2 = new Vue({
el:"#example-2",
data:{
name:'zs'
},
methods:{
greet(event){
// `event` 是原生 DOM 事件
//alert(event.target.tagName);
}
}
});
new Vue({
el:"#example-3",
data:{
name:'zs'
},
methods:{
say(mess){
alert(mess);
// `event` 是原生 DOM 事件
//alert(event.target.tagName);
},
warn(mess,event){
// 现在我们可以访问原生事件对象
if (event) {
event.preventDefault()
}
alert(mess);
}
}
});
new Vue({
el:"#example-4",
methods:{
doThis(){
alert("执行到了a的click");
},
doDivClick(){
alert("执行到了div的click");
}
}
});
new Vue({
el:"#example-5",
data:{
name:'zs'
},
methods:{
submit(){
alert(this.name);
}
}
});
//alert(vue2.name);
//vue2.greet();
script>
body>
html>
<html>
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
head>
<body>
<div id="app">
<h2>文本h2>
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}p>
<p style="white-space: pre-line;">{{ message }}p>
<br>
<h2>文本域h2>
<textarea v-model="message" placeholder="add multiple lines">textarea>
<h2>复选框h2>
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}label>
<h2>多个复选框,绑定到同一个数组:h2>
<div >
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jacklabel>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">Johnlabel>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mikelabel>
<br>
<span>Checked names: {{ checkedNames }}span>
div>
<h2>单选按钮h2>
<div >
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">Onelabel>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Twolabel>
<br>
<span>Picked: {{ picked }}span>
div>
<h2>选择框h2>
<div >
<select v-model="selected">
<option disabled value="">请选择option>
<option>Aoption>
<option>Boption>
<option>Coption>
select>
<span>Selected: {{ selected }}span>
div>
<H2>多选选择框H2>
<div >
<select v-model="selecteds" multiple style="width: 50px;">
<option>Aoption>
<option>Boption>
<option>Coption>
select>
<br>
<span>Selected: {{ selecteds }}span>
div>
<h2>用 v-for 渲染的动态选项:h2>
<select v-model="selected">
<option v-for="option in options" :value="option.value">
{{ option.text }}
option>
select>
<span>Selected: {{ selected }}span>
<h2>值绑定h2>
<pre>对于单选按钮,复选框及选择框的选项,v-model 绑定的值通常是静态字符串 (对于复选框也可以是布尔值):pre>
<input type="radio" v-model="picked" value="a"> {{picked}}
<input type="checkbox" v-model="toggle" true-value="yes"> {{toggle}}
<select v-model="selected">
<option value="abc">ABCoption>
select>
{{selected}}
<h2>单选按钮h2>
<input type="radio" v-model="pick" v-bind:value="a"> {{pick}}
<h2>选择框的选项h2>
<select v-model="selectedobj">
<option v-bind:value="{ number: 123 }">123option>
select>
{{selectedobj.number}}
<h2>修饰符h2>
<input v-model.lazy="msg" > {{msg}}
<input v-model.number="age" type="number">
<%--如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:--%>
<input v-model.trim="msg">
div>
<script type="text/javascript">
new Vue({
el:"#app",
data:{
message:"",
checked:'',
checkedNames: [],
picked:'',
selected: 'B',
selecteds:[],
options:[
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' }
],
toggle:'',
a:'xxx',
pick:'ooo',
selectedobj:{},
msg:''
}
});
script>
body>
html>
<html>
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
head>
<body>
<div id="app">
<button-counter :title="msg" @event="fun1">
<p>这是一个pp>
button-counter>
<button-counter :title2="msg2">button-counter>
<button-counter>button-counter>
div>
<script type="text/javascript">
Vue.component('button-counter',{ // 创建一个全局组件 组件的名字是 button-counter
//props:['title'], /*父组件向子组件传值*/
props:{
title:{
type:String,
default:'默认值'
},
title2:{
type:String,
default:''
},
},
data:function () {
return {
count:0
}
},
methods:{
clickFun(){
this.count++;
this.$emit('event',this.count); // 触发 父组件的事件
}
},
template:'h1...
'
});
new Vue({
el:"#app",
data:{
msg:'标题1',
msg2:'标题2'
},
methods:{
fun1(count){
console.log('子组件向父组件传参'+count);
}
}
});
/*
* 组件的概念
* 如何创建全局组件
* 组件的模板只能有一个根元素
* props 取值 赋值(父组件向子组件赋值)
* */
script>
body>
html>
<html>
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
head>
<body>
<div id="blog-post-demo">
<hr>
<div :style="{ fontSize: postFontSize + 'em' }">
<blog-post @enlarge-text="onEnlargeText"
v-for="post in posts"
v-bind:key="post.id"
v-bind:title="post.title"
v-bind:content="post.content"
v-bind:post="post"
>blog-post>
div>
<hr>
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
v-model="searchText"
>custom-input>
<hr>
<component-a title="这是局部组件">component-a>
div>
<script type="text/javascript">
Vue.component('blog-post', {
//props: ['title','content'],
props: ['post'],
template: '{{ post.title }}
' +
''
,methods:{
clickFun(){
this.$emit('enlarge-text',0.1);
}
}
})
Vue.component('custom-input', {
props: ['value'],
template: ``
})
new Vue({
el: '#blog-post-demo',
data: {
posts: [
{ id: 1, title: 'My journey with Vue' ,content:'content1',comments:'评论1'},
{ id: 2, title: 'Blogging with Vue' ,content:'content2',comments:'评论2'},
{ id: 3, title: 'Why Vue is so fun' ,content:'content3',comments:'评论3'}
],
postFontSize: 1,
searchText:''
},
methods:{
onEnlargeText(enlargeAmount) {
this.postFontSize += enlargeAmount;
}
},
components:{
'component-a':{
props: ['title'],
template: '{{title}}
'
}
}
})
script>
<style type="text/css">
.blog-post{
border: 1px solid black;
}
style>
body>
html>
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
生命周期主要有三个阶段:
一,初始化显示;(重要勾子 mounted 网页加载完毕触发)
二,更新显示;(重要勾子beforeUpdate 数据属性更新前)
三,死亡;(重要勾子beforeDestroy vm死亡前)
每个生命周期都会有对应的生命周期的函数,或者叫做勾子函数;
<html>
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
head>
<body>
<pre>每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、
将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,
这给了用户在不同阶段添加自己的代码的机会。pre>
<div id="app">
<p>{{name}}p>
<button @click="update">updatebutton>
<button @click="destroy">destroybutton>
div>
<script type="text/javascript">
new Vue({
el:"#app",
data:{
a:1,
name:"zs"
},
methods:{
update(){
this.name = Math.random() +"---";
},
destroy(){
this.$destroy();
}
},
beforeCreate(){
console.log("创建vue实例之前");
},
created(){
//
console.log("vue实例创建成功");
console.log(this.a);
}
/* created: () => console.log(this.a)*/
,
beforeMount(){
console.log("vue对象挂载之前");
},
mounted(){
// 只执行一次 页面加载完之后执行 比如 咱们在 页面加载完毕 发送ajax请求 获取数据
console.log(" mounted 挂载完毕")
},
beforeUpdate(){
// 可执行多次
console.log("data更新之前执行");
},
updated(){
// 可执行多次
console.log("data更新之后执行");
},
beforeDestroy(){
// 只执行一次
console.log("vue实例销毁之前执行");
},
destroyed(){
// 只执行一次
console.log("vue实例销毁之后执行");
}
});
script>
body>
html>
<!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>
<script src="../js/vue.js"></script>
<script src="../js/axios.min.js"></script>
</head>
<body>
<div id="app">
<p>
vue中使用ajax请求 <br>
-- axios <br>
-- vue-resource 用得不多
</p>
<table>
<tr>
<td>编号</td>
<td>名字</td>
<td>年龄</td>
<td>邮箱</td>
</tr>
<tr v-for="user in users">
<td>{{user.id}}</td>
<td>{{user.name}}</td>
<td>{{user.age}}</td>
<td>{{user.email}}</td>
</tr>
</table>
</div>
</body>
<script type="text/javascript">
new Vue({
el: "#app",
data: {
users: [
{
id: 1,
name: "张三",
age: 18,
email: "[email protected]"
}
]
},
methods: {
getUsers() {
//let _this = this; // 这里的this代表当气前 vue 实例
// 发送ajax请求 获取数据
// 为给定 ID 的 user 创建请求
// axios.get('http://localhost:8080/user/users?token=123')
// .then(function (response) {
// console.log(response);
// console.log(response.data.data);
// _this.users = response.data.data;
// })
// .catch(function (error) {
// console.log(error);
// });
// axios.get("http://localhost:8080/user/users?token=123")
// .then((response) => {
// console.log(response);
// console.log(response.data.data);
// this.users = response.data.data;
// })
// .catch((error) => {
// console.log(error);
// })
axios.post('http://localhost:8080/user/users?token=123', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then((response)=>{
this.users = response.data.data;
})
.catch(function (error) {
console.log(error);
});
}
},
mounted() {
this.getUsers();
}
})
</script>
</html>
准备工作:安装好 nodejs 安装好vscode 安装过程中可能出现的问题 百度可解决
有版本号就正常,安装Node的时候,npm包管理工具也是一并安装的
查看 npm 的 版本 : npm -v
可以再安装 cnpm 这个工具 ,使用它 下载东西较快, 这里 咱们安装的版本是 8.3.0 ,安装最新版 可能会出问题
npm install -g [email protected] --registry=https://registry.npm.taobao.org
安装vue-cli 安装一次即可 安装时间很漫长
cnpm install -g @vue/cli //安装的是新版本 新版本 支持 vue ui
注意 这里的安装可能需要管理员权限
安装完了之后 可能被windows的安全策略限制 参考
VSCode报错:vue : 无法加载文件 D:\nodejs\node_global\vue.ps1,因为在此系统上禁止运行脚本。_没有咸鱼的梦想的博客-CSDN博客
1.使用vue脚手架创建vue 项目,创建的方式 可以通过指令 也可以通过 vue ui
这里 咱们通过 vue ui 来创建,建议大家使用 管理员 来进行操作
创建项目 不保存预设 然后 后台就开始下载文件
创建好之后 页面跳转到仪表盘
可以在这里 安装一些插件 比如 axios element-ui 等等
这是已经安装的插件
点 添加插件 搜索 element-ui
搜索 axios 点安装
安装 ajax 插件 axios,
然后 可以关掉仪表盘,使用vscode 打开 刚才创建的工程 使用 vue run serve 启动工程,
下图是 低版本的 工程结构
这个是咱们 所创建的工程结构
一般 咱们会使用 用户代码片段 去写这个页面
文件-》首选项-》配置用户代码片段-》新建全局代码片段文件-》把下面的代码粘贴进去
{
"生成vue模板": {
"prefix": "vue",
"body": [
"",
"",
"",
"",
"",
""
],
"description": "生成vue模板"
}
}
在vscode 中 启动 vue 工程,
停止 ctrl + c
引入
GllsDemo1.vue
{{title}}
百度
GllsDemo2.vue
{{ post.title }}
App.vue
这是一个p,通过插槽传递过去
总结: 父组件 向 子组件 传递 数据 ,这个数据 可以是 属性 也可以是 方法 好好体会下
props 方式 传递数据
子组件
父组件
emit 方式 调用父组件方法
参考上文代码
我们前面讲了父子组件之间通过prop来实现消息传递;但是再其他情况,比如兄弟组件,爷孙组件消息传递时候,就要用到高级的消息订阅与发布;
1.首先我们安装下消息订阅与发布pubsub组件;
cnpm install --save pubsub-js
2.把 pubsub 配置成全局组件 在 main.js 中配置
- 在 父组件中 订阅消息 可以在 mounted 钩子函数中 监听消息
在这里 使用了 箭头函数 => ,在箭头函数中 的 this 代表 当前 vue 对象,如果 使用一般函数 ,那么在这个函数内 this 就代表PubSub对象,所以 在这里 咱们使用 =>箭头函数
在别的组件中 发布消息
注意: 执行上面的案例 会发现 订阅消息的回调函数 执行了两次 , 我们需要在我们每次接受数据pubsub.subscribe的时候,先执行pubsub.unsubscribe操作就好了,就完美解决了,这样你接收以后的callback只执行一次
PubSub.unsubscribe();
PubSub.subscribe(eventName, callback); //这样 回调就只执行一次
父组件向子组件传递标签,通过slot 插槽实现
主要作用:
某一个区块,先占位,然后可以动态的搞个标签进去,方便切换该位置的内容,无需再搞多个页面;
父组件 直接定义标签p 注意 slot 属性
子组件 使用 slot 标签 占位置 注意 slot 标签的name 属性,当父组件没有传对应的插槽(属性值对应)内容时,会显示插槽默认内容
vue的ajax框架有vue-resource和axios;vue-resource插件非官方库,axios是ajax通用请求库,vue官方推荐;
在这里,咱们先只研究axios
axios 的用法
https://github.com/axios/axios
安装 咱们 已经在 vue ui 中 安装过了
创建GllsDemo4.vue
<template>
<div>
<input type="text" v-model="name"> <button @click="getUsers()">查询button>
<table>
<tr>
<td>编号td>
<td>名字td>
<td>年龄td>
<td>邮箱td>
tr>
<tr v-for="user in users" :key="user.id">
<td>{{user.id}}td>
<td>{{user.name}}td>
<td>{{user.age}}td>
<td>{{user.email}}td>
tr>
table>
div>
template>
<script>
export default {
name:"GllsDemo4",
data(){
return {
name:'',
users: [
{
id: 1,
name: "zs",
age: 18,
email: "[email protected]"
}
]
}
},
methods:{
getUsers() {
axios.post("http://localhost:8088/user/users",{name:this.name})
.then((res) => {
this.users = res.data.data.users;
})
.catch(function (error) {
console.log(error);
})
}
},
mounted(){
this.getUsers();
}
}
script>
<style>
style>
准备 后台 接口 需要 注意 前后端交互 问题
请求 方式 ?
携带参数的方式?
跨域问题?
后端怎么接参数 ? 、
后端响应的数据结构是什么?
前端怎么接后端相应的数据
vue Router路由组件是vue的核心组件; 平时我们通过路由组件来实现导航菜单以及各种页面切换;我们在安装vue-cli 的时候 安装了这个组件,如果一开始没有安装 也可以通过 npm install vue-router --save 来安装。
这里 咱们已经安装好了vue router,并且vue-cli 已经自动帮助咱们配置好了 ,咱们直接使用即可
在main.js 中的 router 配置, 咱们 用 vue ui 安装的时候 已经自动配置到 main.js 了
import router from './router'
new Vue({
el: '#app',
router,
components: { App },
template: ' '
})
在 router文件夹下 的index.js 是 路由的配置文件
创建views 文件夹 其下面创建Index.vue 和 Menu1.vue
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Index from '@/views/Index'
import Menu1 from '@/views/Menu1'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/index',
name: 'Index',
component: Index
},
{
path: '/menu1',
name: 'Menu1',
component: Menu1
}
]
})
在App.vue 中的路由写法
<div class="menu">
<ul>
<li>
<router-link to="/index">首页router-link>
li>
<li>
<router-link to="/menu1">菜单1router-link>
li>
ul>
div>
<div class="content">
<router-view>router-view>
div>
<style scoped>
/* 这里的scoped 是 设置 样式作用范围 如果加上 scoped 就 只作用于当前页面
如果不加 scoped 就会影响 他的 路由视口页面
*/
ul li{
float: left;
list-style: none;
padding-left: 30px;
}
.content{
clear: both;
}
style>
通过 router-link 向路由配置发送请求 ,结果会在 router-view 显示
Menu1.vue 继续嵌套 下级页面 配置嵌套路由
Menu1.vue
<div>
{{msg}}
<ul>
<li>
<router-link to="/menu1/submenu1">子菜单1router-link>
li>
<li>
<router-link to="/menu1/submenu2">子菜单2router-link>
li>
ul>
<div class="content">
<router-view>router-view>
div>
div>
在路由配置文件中
{
path: '/menu1',
name: 'Menu1',
component: Menu1,
children:[ // 子路由
{
path:'/menu1/submenu1', // 当然 对应的 子组件 得创建好
component: () => import('@/views/SubMenu1.vue') // 这样就不用在文件上面配置了
},
{
path:'/menu1/submenu2',
component: () => import('@/views/SubMenu2.vue')
},
{
path:'',
redirect:'/menu1/submenu1' // 默认显示submenu1
}
]
},
SubMenu1.vue
<template>
<div>子菜单1
<input type="text" name="sub1input">
div>
template>
SubMenu2.vue
<template>
<div>子菜单2
<input type="text" name="sub2input">
div>
template>
当我们 在 子菜单1 和 子菜单2 的 文本输入框输入内容时,发现 跳转之后内容没有了,这种情况也经常遇到
我们切换不同的组件时,希望 组件内输入的内容不要丢失 ,怎么解决?只需要 使用keep-alive 标签
在App.vue 添加 用户信息 路由菜单 , 配置 路由配置文件
{
path: '/user',
name: 'user',
component: () => import('../views/User.vue'),
},
用户信息组件 User.vue
<table>
<tr>
<th>编号th>
<th>用户名th>
<th>密码th>
tr>
<tr v-for="(user,index) in users" v-bind:key="index">
<td>{{user.id}}td>
<router-link :to="`/user/subUser/${user.id}`"><td>{{user.userName}}td>router-link>
<td>{{user.password}}td>
tr>
table>
路由配置
{
path: '/user',
name: 'user',
component: () => import('../views/User.vue'),
children:[
{
path:'/user/subUser/:id', // 当然 对应的 子组件 得创建好
component: () => import('@/views/SubUser.vue') // 这样就不用在文件上面配置了
},
]
},
SubUser.vue
<template>
<div>
Id:{{$route.params.id}}<br/>
{{user.userName}}<br/>
{{user.password}}<br/>
div>
template>
<script>
export default {
name:"SubMenu",
data(){
return {
user:{}
}
},
methods: {
getUserById(id){
axios.get(`http://localhost:8088/user/user/${id}`)
.then((res) => {
console.log(res);
this.user = res.data.data.user;
})
.catch(function (error) {
console.log(error);
})
}
},
mounted(){
let id=this.$route.params.id;
console.log(id);
this.getUserById(id);
},
watch: {
$route(value){
let id=value.params.id;
this.getUserById(id);
}
},
}
script>
<style>
style>
<template>
<div>
<div>
用户列表
<table>
<tr>
<th>编号th>
<th>用户名th>
<th>密码th>
<th>测试编程式路由th>
tr>
<tr v-for="(user,index) in users" v-bind:key="index">
<td>{{user.id}}td>
<router-link :to="`/user/subUser/${user.id}`"><td>{{user.userName}}td>router-link>
<td>{{user.password}}td>
<td>
<button @click="pushShow(user.id)">push显示button>
<button @click="replaceShow(user.id)">replace显示button>
td>
tr>
table>
<button @click="$router.back()">回退button>
div>
<hr>
<router-view>router-view>
div>
template>
<script>
export default {
name:"User",
data(){
return {
users:[]
}
},
methods:{
pushShow(id){
console.log(id);
this.$router.push(`/user/subUser/${id}`)
},
replaceShow(id){
this.$router.replace(`/user/subUser/${id}`)
}
},
mounted(){
this.$http.get('user/findAll',{"id":1},(res)=>{
this.users = res.data;
})
}
}
script>
<style scoped>
ul li{
clear: both;
}
style>>
Vuex 是一个专为Vue.js 应用程序开发的状态管理模式。https://vuex.vuejs.org/zh/
简单地说 在复杂应用中 Vuex 对vue 应用中的多个组件的共享状态进行集中式管理。
步骤
1.先创建一个没有使用 vuex的组件 MyVuex.vue
<p>当前数字: {{number}} is {{evenOrOdd}}p>
<button v-on:click="jia()">加button>
<button @click="jian()">减button>
data() {
//这里存放数据
return {
number:0
};
},
methods: {
jia(){
this.number++
},
jian(){
this.number--
}
},
computed: {
evenOrOdd(){
return this.number%2==0?'偶数':'奇数'
}
},
就有了计数器的效果
但是 如果项目里 需要多个组件 共享这个 number 的值 ,也就是 number 的变化 很多组件都能感知到 怎么实现,vuex 状态集中式管理 就是解决这个问题的
首先 安装
npm install vuex --save
修改
main.js
文件,导入 Vuex,关键代码如下:
import Vuex from 'vuex'
Vue.use(Vuex);
创建vuex配置文件 在 src 目录下创建一个名为 store 的目录并新建一个名为 index.js 文件用来配置 Vuex,代码如下:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
// 全局 state 对象,用于保存所有组件的公共数据
const state = {
// 在组件中是通过 this.$store.state.number 来获取
number:0
};
// 实时监听 state 值的最新状态,注意这里的 getters 可以理解为计算属性
const getters = {
// 在组件中是通过 this.$store.getters.evenOrOdd 来获取
evenOrOdd(state){
return state.number%2==0 ? '偶数' : '奇数'
}
};
// 定义改变 state 初始值的方法,这里是唯一可以改变 state 的地方,缺点是只能同步执行
const mutations = {
// 在组件中是通过 this.$store.commit('jia'); 方法来调用 mutations
jia(state){
state.number++
},
jian(state){
state.number--
}
};
// 定义触发 mutations 里函数的方法,可以异步执行 mutations 里的函数
const actions = {
// 在组件中是通过 this.$store.dispatch('jia'); 来调用 actions
jia(context){
context.commit('jia')
},
// 在组件中是通过 this.$store.dispatch('jian'); 来调用 actions
jian({commit,state}){ //解构 context 对象 可以拿到对象属性 commit 和 state
if(state.number>0){
commit('jian')
}
}
};
export default new Vuex.Store({
state,
getters,
mutations,
actions
});
修改 main.js 增加刚才配置的 store/index.js,关键代码如下:
import Vue from 'vue'
import Vuex from 'vuex'
import store from './store'
Vue.use(Vuex);
new Vue({
el: '#app',
store
});
修改MyVuex.vue
<p>当前数字: {{$store.state.number}} is {{$store.getters.evenOrOdd}}p>
<button v-on:click="jia()">加button>
<button @click="jian()">减button>
methods: {
jia(){
this.$store.dispatch('jia') // 调用 actions 中的方法
},
jian(){
this.$store.dispatch('jian')
}
},
依然 可以实现之前的效果
但是感觉 每次 都写 $.store.xxx.xxx 太长了 ,怎么办?
// 不想每次都写 $store.state.xxx 就导入组件 然后 计算属性
// 第一步
import {mapState,mapGetters,mapActions} from 'vuex'
//计算属性 类似于data概念
computed: {
// evenOrOdd(){
// return this.number%2==0?'偶数':'奇数'
// }
// 第二步
...mapState(['number']),
...mapGetters(['evenOrOdd']) // 如果 名字不一致
//...mapGetters({'evenOrOdd':'evenOrOdd222'}) // 如果 名字不一致 vuex 中的 getters 内部的方法名 为 evenOrOdd222 不建议这样写
},
methods: {
// jia(){
// this.number++
// },
// jian(){
// this.number--
// }
//jia(){
// this.$store.dispatch('jia')
//},
//jian(){
// this.$store.dispatch('jian')
//}
...mapActions(['jia','jian'])
},
<div>
<p>当前数字: {{number}} is {{evenOrOdd}}p>
<button v-on:click="jia()">加button>
<button @click="jian()">减button>
div>
Vuex 的状态存储是响应式的,当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。但是有一个问题就是:vuex 的存储的数据只是在页面的中,相当于我们定义的全局变量,刷新之后,里边的数据就会恢复到初始化状态。但是这个情况有时候并不是我们所希望的。
监听页面是否刷新,如果页面刷新了,将 state 对象存入到 sessionStorage 中。页面打开之后,判断 sessionStorage 中是否存在 state 对象,如果存在,则说明页面是被刷新过的,将 sessionStorage 中存的数据取出来给 vuex 中的 state 赋值。如果不存在,说明是第一次打开,则取 vuex 中定义的 state 初始值。
在 App.vue 中增加监听刷新事件
export default {
name: 'App',
mounted() {
window.addEventListener('unload', this.saveState);
},
methods: {
saveState() {
sessionStorage.setItem('state', JSON.stringify(this.$store.state));
}
}
}
修改 store/index.js 中的 state
const state = sessionStorage.getItem('state') ? JSON.parse(sessionStorage.getItem('state')) : {
user: {
name: ''
}
};
思考: 此时 复制 MyVuex.vue 组件 复制出来一个新的 MyVuex2.vue , 访问 这两个 页面 为什么 number 的值 却没有共享?
vuex 和 vuex 2 中 number 的值怎么不一致? 注意 这是两个窗口 相当于是两个人,所以不一致, 再试试在一个窗口 进行页面跳转 就会发现一致了
Webpack是一个前端资源的打包工具,它可以将js、image、css等资源当成一个模块进行打包。
从图中我们可以看出,Webpack可以将js、css、png等多种静态资源进行打包,使用webpack有什么好处呢?
1、模块化开发程序员在开发时可以分模块创建不同的js、css等小文件方便开发,最后使用webpack将这些小文件打包成一个文件,减少了http的请求次数。webpack可以实现按需打包,为了避免出现打包文件过大可以打包成多个文件。
2、编译typescript、ES6等高级js语法随着前端技术的强大,开发中可以使用javascript的很多高级版本,比如:typescript、ES6等,方便开发,webpack可以将打包文件转换成浏览器可识别的js语法。
3、CSS预编译webpack允许在开发中使用Sass和Less等原生CSS的扩展技术,通过sass-loader、less-loader将Sass和Less的语法编译成浏览器可识别的css语法
4.使用vue.js开发大型应用需要使用webpack打包工具
node.js 可以把它理解成前端项目的 开发运行环境,就像 java项目的 jdk一样。
这个咱们前面安装过了,安装步骤 简单 详细步骤 可查阅前面的资料。
npm全称NodePackageManager,他是node包管理和分发的工具,使用NPM可以对应用的依赖进行管理, NPM的功能和服务端项目构建工具maven差不多,我们通过npm可以很方便地下载js库,打包js文件。 node.js已经集成了npm工具,在命令提示符输入npm-v可查看当前npm版本
包路径就是npm从远程下载的js包所存放的路径。使用npmconfigls查询NPM管理包路径(NPM下载的依赖包所存放的路径) 这个 也是 查看前面的资料 有详细配置
npm默认会去国外的镜像去下载js包,在开发中通常我们使用国内镜像,这里我们使用淘宝镜像
下边我们来安装cnpm:有时我们使用npm下载资源会很慢,所以我们可以安装一个cnmp(淘宝镜像)来加快下载速度。
输入命令,进行全局安装淘宝镜像。
npm install -g cnpm --registry=https://registry.npm.taobao.org
安装后,我们可以使用以下命令来查看cnpm的版本
cnpm -v
nrm ls 查看镜像已经指向 taobao
命令: nrm use XXX 切换镜像
如果nrm没有安装则需要进行全局安装: cnpm install -g nrm
如果执行 nrm 出异常 nrm ls报错:The “path” argument must be of type string. Received undefined 参考下面解决方案
https://www.jianshu.com/p/126ba674e395
const NRMRC = path.join(process.env[(process.platform == ‘win32’) ? ‘USERPROFILE’ : ‘HOME’], ‘.nrmrc’);
此句话的意思是更具不同的系统平台获取不同的路径。
webpack安装分为本地安装和全局安装:
仅将webpack安装在当前项目的node_modules目录中,仅对当前项目有效。
只在我的项目中使用webpack,需要进行本地安装,因为项目和项目所用的webpack的版本不一样。本地安装就会将webpack的js包下载到项目下的npm_modeuls目录下。
在门户目录下创建webpack测试目录webpacktest01:
npm install --save-dev webpack 或 cnpm install --save-dev webpack
npm install --save-dev webpack-cli (4.0以后的版本需要安装webpack-cli)
将webpack安装在本机,对所有项目有效,全局安装会锁定一个webpack版本,该版本可能不适用某个项目。全局安装需要添加-g参数。
全局安装就将webpack的js包下载到npm的包路径下。
npm install webpack -g 或 cnpm install webpack -g
本教程使用webpack3.6.0,安装webpack3.6.0:
进入webpacktest测试目录,运行:cnpm install --save-dev [email protected]
全局安装:npm install [email protected] -g 或 cnpm install [email protected] -g
通过本入门程序体会webpack打包的过程及模块化开发的思想
需求分析通过入门程序实现对js文件的打包,体会webpack是如何对应用进行模块化管理。
对上边1+1=2的例子使用webpack进行模块化管理
定义模块
创建webpacktest01目录,将vue.min.js及vue_02.html拷贝到目录下。
1、定义model01.js在webpacktest01目录下创建model01.js 将本程序使用的加法运算的js方法抽取到一个js文件,此文件就是一个模块
// 定义 add 函数
function add(x,y){
return x+y;
}
//function add2(x,y) {
// return x+y+2;
//}
//导出add 方法
module.exports.add = add;
// module.exports ={add,add2};//如果有多个方法这样导出
// module.exports.add2 = add2//如果有多个方法也可以这样导出
定义main.js
在webpacktest01目录下创建main.js,main.js是本程序的js主文件,包括如下内容:
1、在此文件中会引用model01.js模块
2、引用vue.min.js(它也一个模块)
3、将html页面中构建vue实例的代码放在main.js中。
main.js的代码如下
var {add} = require('./model01');
var Vue = require('./vue.min');
var VM = new Vue({
el:"#app",
data:{
name:'高级程序员',// 相当于是MVVM中的Model这个角色
num1:0,
num2:0,
result:0,
url:'http://www.lxw.cn'
},
methods:{
change:function(){//这里使用了导入的model01.js文件中的add方法
this.result = add(Number.parseInt(this.num1),Number.parseInt(this.num2));
alert(this.result) }
}
});
打包测试
上边将mode01.js模块及main.js主文件编写完成,下边使用webpack对这些js文件进行打包
1、进入程序目录,执行webpack main.js build.js ,这段指令表示将main.js打包输出为build.js文件执行完成,观察程序目录是否出现build.js。
2、在html中引用build.js
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue.js常用指令的测试title>
head>
<body>
<div id="app">
<a v-bind:href="url">
<span v-text="name">span>
a>
<input type="text" v-model="num1"/> +
<input type="text" v-model="num2"/>=
<span v-text="result">span>
<button v-on:click="change">计算button>
div>
body>
<script src="build.js">script>
<script>
//编写MVVM中的model部分及VM(ViewModel)部分
script>
html>
测试总结
测试功能:
1)输入任意加数,其和会自动计算
2)点击“计算”会调用model01.js中的add方法
总结:webpack可以将js分模块开发,开发完成对各模块代码打包成一个统一的文件。前端模块开发的思想和服务端模块开发的思想是一致的,有利于多人协助开发。
webpack-dev-server开发服务器,它的功能可以实现热加载并且自动刷新浏览器。创建一个新的程序目录,
这里我们创建webpacktest02目录,将webpack入门程序的代码拷贝进来,并在目录下创建src目录、dist目录。将main.js和model01.js vue.js 拷贝到src目录。
安装配置 安装webpack-dev-server
使用webpack-dev-server需要安装webpack、webpack-dev-server和html-webpack-plugin三个包。cnpm install [email protected] [email protected] [email protected] --save-dev安装完成,会发现程序目录出现一个package.json文件,此文件中记录了程序的依赖。执行下面的命令:
cnpm install [email protected] [email protected] [email protected] --save-dev
配置webpack-dev-server
在package.json中配置script
{
"scripts": {
"dev": "webpack-dev-server --inline --hot --port 5008"
},
"devDependencies": {
"html-webpack-plugin": "^2.30.1",
"webpack": "^3.6.0",
"webpack-dev-server": "^2.9.1"
}
}
devDependencies:开发人员在开发过程中所需要的依赖。
scripts:可执行的命令
配置webpack.config.js
在webpacktest02目录下创建webpack.config.js,webpack.config.js是webpack的配置文件。在此文件中可以配置应用的入口文件、输出配置、插件等,其中要实现热加载自动刷新功能需要配置html-webpack-plugin插件。html-webpack-plugin的作用是根据html模板在内存生成html文件,它的工作原理是根据模板文件在内存中生成一个index.html文件。
1、配置模板文件将原来的vue_02.html作为模板文件,为了和内存中的index.html文件名区别,注意将vue_02.html中的script标签去掉,内容如下:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue.js常用指令的测试title>
head>
<body>
<div id="app">
<a v-bind:href="url">
<span v-text="name">span>
a>
<input type="text" v-model="num1"/> +
<input type="text" v-model="num2"/>=
<span v-text="result">span>
<button v-on:click="change">计算button>
div>
body>
html>
配置html-webpack-plugin
在webpack.config.js中配置html-webpack-plugin插件
var htmlwp=require('html-webpack-plugin');
module.exports={
entry:'./src/main.js', //指定打包的入口文件
output:{
path:__dirname+'/dist', //注意:__dirname表示webpack.config.js所在目录的绝对路径
filename:'build.js' //输出文件
},
devtool: 'eval-source-map',
plugins:[
new htmlwp({
title:'首页', //生成的页面标题首页
filename:'index.html', //webpack‐dev‐server在内存中生成的文件名称,自动将build注入到这个页面底部,才能实现自动刷新功能
template:'vue_02.html' //根据 vue_02.html 这个模板来生成(这个文件请程序员自己生成)})]}
})
]
}
启动
启动文件:
1、进入webpacktest02目录,执行npm run dev
2、使用webstorm,右键package.json文件,选择“Show npm Scripts”打开窗口:
degug调试
使用了webpack之后就不能采用传统js的调试方法在chrome中打断点
webpack将多个源文件打包成一个文件,并且文件的内容产生了很大的变化,webpack提供devtool进行调试,devtool是基于sourcemap的方式,在调试时会生成一个map文件,其内容记录生成文件和源文件的内容映射,即生成文件中的哪个位置对应源文件中的哪个位置,有了sourcemap就可以在调试时看到源代码。
配置如下:
1、在webpack.config.js中配置: