01-HelloVuejs.html
Title
Hello {{message}}
运行结果
02-vue列表展示.html
Title
- {{item}}
{{movies}}
运行结果
mustache 体验Vue响应式
Vue列表展示
movies:[‘大话西游’,‘星际穿越’,‘少年派’,‘违背’]
v-for
{{movies}}
- {{item}}
后面的数组追加元素的时候,新的元素也可以在界面上渲染出来,并且是响应式的
03-vue案例-计数器.html
Title
当前计数: {{counter}}
Model(JS)+View(DOM) +ViewModel(VUE)
View层
Model层
ViewModel层
el:
document.querySelector(HTMLElement)
类型:String|HTMLElement
作用:决定之后Vue实例会管理哪一个DOM
data:
类型:Object|Function(组件中必须是一个函数)
作用:Vue实例对应的数据对象
methods:
类型:{[key:string]: Function}
作用:定义属于Vue的一些方法,可以在其他地方调用,也可以在指令中使用
方法和函数
生命周期函数
mustache语法中不仅仅可以直接写变量,也可以写简单的表达式
01-Mustache语法.html
Title
{{ message }}
{{ message }},李银河
{{ firstName + lastName }}
{{ firstName + ' ' + lastName }}
{{ firstName}} {{lastName}}
{{ counter * 2}}
运行结果
在开发中,有时候只需要第一次的时候去改变,之后在改变
该指令后面不需要跟任何表达式(比如v-for后面是要跟表达式的)
该指令表示元素和组件只渲染一次,不会随着数据的改变而改变
02- v-once的使用.html
Title
{{ message }}
{{ message }}
运行结果
某些情况下,我们从服务器请求到的数据本身就是一个HTML代码,如果我们直接通过{{}}来输出,会将HTML代码也一起输出
此时,我们可以使用V-htm指令
03-v-html的使用.html
Title
v-text作用和Mustache比较相似:都是用于将数据显示在页面中
v-text通常情况下,接受一个string类型
04-v-text的使用.html
Title
{{ message }},李银河
,李银河
v-pre用于跳过这个元素和它子元素的编译过程,用于显示原本的Mustache语法
Title
{{ message }}
{{ message }}
运行结果
在某些情况下,我们浏览器可能会直接显示出未编译的Mustache标签
Title
{{ message }}
前面学习的指令主要作用是将值插入到我们模板的内容当中
但是,除了内容需要动态来决定外,某些属性我们也希望动态来绑定
这个时候,我们可以使用v-bind指令:
v-bind用于绑定一个或多个属性值,或者向另一个组件传递props值,在开发中,图片的链接src、网站的链接href,动态绑定的一些类、样式等等
v-bind :str
v-bind:href可简写为: href
Title
基本绑定
{{message}}
动态绑定(多此一举)
{{message}}
后面跟对象(title是固定的,active和line是不固定的)
{{message}}
{{message}}
如果过于复杂,可以放在一个methods或者computed中
{{message}}
getClasses : function(){
return {active: this.isActive, line :this.isLine};
}
02-v-bind动态绑定class属性(对象语法).html
Title
{{message}}
{{message}}
可以传入多个值
{{ message }}
如果过于复杂,可以放在一个methods或者computed中
{{ message }}
methods: {
getClasses: function () {
return [this.active, this.line];
}
}
03-v-bind动态绑定class属性(数组语法).html
Title
{{message}}
{{message}}
Title
{{ message }}
{{ message }}
运行结果
style后面跟的是一个数组类型,多个值以","分割即可
{{ message }}
data:{
message: '你好!',
baseStyle: { backgroundColor: 'red'},
baseStyle1: {fontSize : '100px'}
}
06-v-bind动态绑定style(数组语法).html
Title
{{ message }}
{{ message }}
在模板中可以直接通过插值语法显示一些data中的数据,但是在某些情况下,我们可能需要对数据进行一些转化后再显示,或者需要将多个数据结合起来进行显示,比如我们有firstName和lastName两个变量,我们需要显示完整的名称,但是如果多个地方都需要显示完整的名称,我们就需要写多个{{firstName}}{{lastName}},此时,我们便可以使用计算属性
01-计算属性的基本使用.html
Title
{{ firstName + ' ' +lastName }}
{{ firstName}} {{ lastName }}
{{ getFullName() }}
{{ fullName }}
02-计算属性的复杂操作.html
Title
{{ totalPrice }}
运行结果
补充ES6
for (let i in this.books)
for (let book of this.books)
每一个计算属性都包含一个getter和setter
03-计算属性的setter和getter.html
Title
{{ fullName }}
运行结果
计算属性在多次使用时,只会调一次,它是有缓存的,methods在多次使用时,会调用多次,是没有缓存的,性能较低
04-计算属性和methods的对比.html
Title
{{ firstName }} {{lastName}}
{{ getFullName() }}
{{ getFullName() }}
{{ getFullName() }}
{{ getFullName() }}
{{ fullName }}
{{ fullName }}
{{ fullName }}
{{ fullName }}
运行结果
一旦给const修饰的标识符被赋值后,不能修改
在使用const定义标识符,必须进行赋值
const name;//×
常量的含义是指向的对象不能修改,但是可以改变对象内部的属性
const obj = {
name : 'Kobe',
age : 18,
height :1.88
}
console.log(obj);
obj.name ='Kobe';
obj.age = 10,
obj.height='1.88'
属性的增强写法
const name = 'why';
const age = '18';
const height = '1.88';
//ES5 的写法
const obj = {
name : name,
age : age ,
height : height
}
//ES6的写法
const obj = {
name,
age ,
height
}
console.log(obj);
函数的增强写法
//ES5的增强写法
const obj = {
run : function () {
console .log ('在本派');
},
eat : function () {
console.log ("在吃东西");
}
}
//ES6的增强写法
const obj = {
run () {
},
eat () {
}
v-on介绍
01-v-on的基本使用.html
Title
{{ counter }}
运行结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ndZ5Hz8H-1644828620582)(C:\Users\JMS\AppData\Roaming\Typora\typora-user-images\image-20220214110659841.png)]
02-v-on的参数问题.html
Title
事件调用的方法没有参数参数传递进去
事件调用的方法有event事件参数
事件调用的方法有event对象和其他参数
stop:阻止冒泡
prevent:阻止默认行为
enter:监听键盘的键帽的点击
once:只触发一次回调
native:监听组件根元素的原生事件
03-v-on修饰符.html
Title
aaaaaaaa
01-v-if的使用.html
Title
{{ message }}
运行结果
02-v-if和v-else结合使用.html
Title
abc
abc
abc
abc
abc
{{ message }}
isShow为fasle时,显示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-97uBjzj2-1644828620584)(C:\Users\JMS\AppData\Roaming\Typora\typora-user-images\image-20220214142438229.png)]
Vue的条件指令可以根据表达式的值在DOM中渲染或销毁元素或组件
v-if的原理
03-v-if和v-else-if和v-else的使用.html
Title
优秀
良好
及格
不及格
{{result}}
运行结果
如果我们在有输入内容的情况下,切换了类型,我们会发现文字依然显示之前的输入内容
这是因为Vue在进行DOM渲染时,出于性能考虑,会尽可能的复用已经存在的元素,而不是重新创建新的元素
如果我们不希望Vue出现类似重复利用的问题,可以给对应的input添加key,并且我们需要保证Key的不同
Title
运行结果
v-show和v-if 的区别
06-v-show的使用.html
Title
{{ message }}
{{ message }}
运行结果
v-for的语法类似于JavaScript中的for循环,格式:item in items的形式
如果在遍历的过程中不需要使用索引值
如果在遍历的过程中,我们需要拿到元素在数组的索引
01-v-for遍历数组.html
Title
- {{item}}
- {{index+1}}.{{item}}
运行结果
在遍历对象的过程中,如果只是获取一个值,那么获取的是value
- {{item}}
获取key和value,格式:(value,key)
- {{value}}-{{key}}
获取key、value和index,格式:(value, key, index)
- {{value}}-{{key}}-{{index}}
02-v-for遍历对象.html
Title
- {{item}}
- {{value}}-{{key}}
- {{value}}-{{key}}-{{index}}
运行结果
通过索引值修改数组的元素不是响应式的
push():数组最后添加元素
this.letters.push('aaa')*/
this.letters.push('aaa','bbb','vvv')
pop():删除数组中的最后一个元素
this.letters.pop();
shift():删除数组中的第一个元素
this.letters.shift();
unshift():给数组最前面添加元素
//this.letters.unshift('aaa');
//this.letters.unshift('aaa','bbb','vvv')
splice()
sort():排序
this.letters.sort();
reverse():反转
this.letters.reverse();
index.html
Title
书籍名称
出版日期
价格
购买数量
操作
{{item.id}}
{{item.name}}
{{item.data}}
{{item.price| showPrice}}
{{item.count}}
总价格:{{totalPrice | showPrice}}
购物车为空
main.js
const app = new Vue({
el: '#app',
data:{
books:[
{
id:1,
name :'《算法导论》',
data:'2006-9',
price:85.00,
count:1
},
{
id:2,
name :'《UNIX编程艺术》',
data:'2006-2',
price:59.00,
count:1
},
{
id:3,
name :'《编程艺术》',
data:'2008-10',
price:39.00,
count:1
},
{
id:4,
name :'《代码大全》',
data:'2006-3',
price:128.00,
count:1
},
]
},
methods:{
getFinalPrice(price){
return '¥' + price.toFixed(2)
},
increment(index){
this.books[index].count++
},
decrement(index){
this.books[index].count--
},
removeHandle(index){
this.books.splice(index,1)
}
},
filters:{
showPrice(price){
return '¥' + price.toFixed(2)
}
},
computed:{
totalPrice(){
//1.普通的for循环
/* let totalPrice=0;
for(let i =0;i
style.css
table{
border : 1px solid #e9e9e9;
border-collapse: collapse;
border-spacing: 0;
}
th,td{
padding:8px 16px;
border :1px solid #e9e9e9;
text-align: left;
}
th{
background-color: #f7f7f7;
color:#5c6b77;
font-weight: 600;
}
高阶函数.js
//编程范式 :编程式编程/声明式编程
//编程范式 :面向对象编程(第一公民是对象)/函数式编程(第一公民是函数)
//高阶函数 filer/map/reduce
//filter中的回调函数有一个要求:必须返回一个bollean值
//true:当返回true时,函数内部会自动将这次回调的n加入到新的数组中
//false:当返回false时,函数内部会过滤掉这次的n
const nums = [10,20,111,222,444,40,50]
/* let newNums = nums.filter(function (n){
return n<100
})
console.log(newNums);
/!*2.map函数的使用*!/
let new2Nums =newNums.map(function (n){
return n * 2;
})
console.log(new2Nums)
//3.reduce函数的使用
//reduce函数的作用:对数组中所有内容汇总
let total = new2Nums.reduce(function (preValue , n){
return preValue + n
},0)*/
//第一次 : preValue:0 n:20
//第二次 : preValue:20 n:40
//第三次 : preValue:60 n:80
//第四次 : preValue:140 n:100
//240
/*let total = nums.filter(function (n){
return n<100
}).map(function (n){
return n*2
}).reduce(function (prevValue , n){
return prevValue+n
},0)*/
let total = nums.filter(n => n< 100).map(n =>n * 2).reduce((pre , n) => pre + n);
console.log(total);
/*
//需求:1.取出所有小于100的数字
let newNums =[]
for (let n of nums){
if(n<100){
newNums.push(n);
}
}
//需求:2.将所有小于100的数字进行转化:全部 *2
let new2Nums = []
for (let n of newNums){
new2Nums.push(n*2)
}
//需求:3.将所有需求new2Nums中的数字相加,得到最终结果
let total = 0
for (let n of new2Nums){
}*/
运行结果
表单控件在实际开发中是非常常见的,特别是对于用户信息的提交,vue中使用v-model指令来实现表单元素和数据的双向绑定
当我们在输入框输入内容时,因为input中的v-model绑定了message,所以会实时将输入的内容传递给message,message 发生改变,当message发生改变时,因为上面使用Mustache语法,将message的值插入到DOM中,所以DOM会发生响应的改变
所以,通过v-model实现了双向的绑定
v-model =>v-bind:value v-on: input
v-model其实是一个语法糖,它的背后本质是包含两个操作
v-bind绑定一个value属性
v-on指令给当前元素绑定input事件
lazy
默认情况下,v-model默认是在input事件中同步输入框的数据的。
也就是说,一旦有数据发生改变对应的data中的数据就会自动发生改变。
lazy修饰符可以让数据在失去焦点或者回车时才会更新
{{message}}
number
默认情况下,在输入框中无论我们输入的是字母还是数字,都会被当做字符串类型进行处理。
但是如果我们希望处理的是数字类型,那么最好直接将内容当做数字处理。
number修饰符可以让在输入框中输入的内容自动转成数字类型
{{age}}--{{typeof(age)}}
trim
06-v-model修饰符的使用.html
Title
{{message}}
{{age}}--{{typeof(age)}}
您输入的名字是:{{name}}
注册组件的基本步骤
//1.创建组件构造器对象
const cpnC = Vue.extend({
template :`
我是标题
我是内容,哈哈哈哈哈
我是内容,呵呵呵呵呵
`
})
//2.注册组件
/*Vue.component('组件的标签名')*/
Vue.component('my-cpn',cpnC)
const app = new Vue({
el: '#app',
data:{
message: '你好!'
}
})
Vue.extend()
Vue.component()
组件必须挂载在某个Vue实例下,否则他不会生效
全局组件
意味着可以在多个Vue的实例下面使用
注册方式
Vue.component('my-cpn',cpnC)
局部组件
意味着只能在该Vue的实例下面使用
注册方式
const app = new Vue({
el: '#app',
data:{
message: '你好!'
},
components :{
//con使用组件时的标签名
//cpnC组件的构造器
cpn :cpnC
}
})
//子组件
const cpnC1 = Vue.extend({
template :`
我是标题1
我是内容,哈哈哈哈哈
`
}
)
//父组件
const cpnC2 = Vue.extend({
template :`
我是标题2
我是内容,呵呵呵呵呵
`
,
components :{
cpn1 : cpnC1,
}
}
)
//root 根组件
const app = new Vue({
el: '#app',
data:{
message: '你好!'
},
components :{
cpn2: cpnC2
}
})
//全局组件的语法糖
Vue.component('cnp1',{
template :`
我是标题1
我是内容,哈哈哈哈哈
`
})
const app = new Vue({
el: '#app',
data:{
message: '你好!'
},
//局部组件的注册语法糖
components:{
'cnp2':{
template :`
我是标题2
我是内容,哈哈哈哈哈
`
}
}
})
script
template
我是标题
我是内容,哈哈哈哈哈
组件是一个单独功能模块的封装,这个模块有属于自己的HTML模板,也应该有属于自己的数据data
组件不能直接访问Vue实例中的data,而且即使可以访问,如果将所有的数据都放在Vue实例中,Vue实例就会变得非常臃肿
组件数据的存放
组件中的data为什么必须是一个函数
Vue.component('cpn',{
template:'#cpn',
//是函数,不会相互影响,每一个组件都用的不同的对象,不会引起连锁反应
data(){
return{
counter :0
}
},
/* //不是函数,会相互影响,因为每一个组件都用的一个对象,会引起连锁反应
const obj = {
counter :0
}
data(){
return obj
},*/
子组件是不能引用父组件或者Vue实例的数据的,但是在开发中,往往一些数据确实需要从上层传递到下层,比如我们从服务器请求到了很多数据,其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示,这个时候,并不会让子组件再发一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)
真实的开发中,Vue实例和子组件的通信和父组件和子组件的通信过程是一样的。
父传子 : props
{{cInfo}}
{{childMyMessage}}
子传父:$emit
Title
npm install
npm run serve/dev
有时候需要父组件直接访问子组件,子组件需要直接访问父组件,或者子组件访问跟组件
父组件访问子组件:使用 c h i l d r e n 或 children或 children或refs
我是子组件
子组件访问父组件:使用$parent
我是子组件
插槽的目的是让我们封装的组件更加具有扩展性
封装插槽的方法:抽取共性,保留不同
插槽的基本使用
插槽的默认值
如果有多个值,同时放入到组件进行替换时,一起作为替换元素
01-插槽的基本使用.html
Title
哈哈哈哈哈哈
呵呵呵呵呵
我是组件
我是组件,哈哈哈哈哈哈
>
运行结果
02-具名插槽.html
Title
标题
左边
中间
右边
运行结果
父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。
03-编译的作用域.html
Title
我是子组件
我是内容,哈哈哈哈
父组件替换插槽的标签,但是内容是由子组件来提供的
04-作用域插槽的案例.html
Title
{{slot.abc.join(' - ')}}
{{slot.abc.join(' * ')}}
- {{item}}
运行结果
模块化有两个核心:导出和导入
CommonJS的导出
module.exports = {
flag: true,
test(a,b){
return a+b
},
demo(a,b){
return a*b
}
}
CommonJS的导入
//CommonJS模块
let {test,demo,flag} = require('moduleA');
//等同于
let _mA = required('moduleA');
let test = _mA.test;
let demo = _mA.demo;
let flag = _mA.flag;
export指令用于导出变量
//info.js
export let name ='why'
export let age = 18
export let height = 1.88
上面的代码还有另外一种写法:
//info.js
let name ='why'
let age = 18
let height = 1.88
export{name,age,height}
export指令用于导出函数/类
export function test(content){
console.log(content)
}
export class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
run(){
console.log(this.name +'在奔跑');
}
}
上面的代码还有另外一种写法:
function test(content){
console.log(content)
}
class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
run(){
console.log(this.name +'在奔跑');
}
}
export{test,Person};
export default
某些情况下,一个模块中包含某个的功能,我们并不希望给这个功能命名,而且让导入者可以自己来命名,这个时候就要用export default
//导出
//info.js
export default function(){
console.log('default funtion');
}
导入
import myFunc form './info.js'
myFunc()
另外,需要注意:
export default在同一模块中,不允许同时存在多个
首先,我们需要在HTML代码中引入两个js文件,并且类型需要设置为module
import指令用于导入模块的内容,比如main.js的代码
import{name,age,height} from "./info.js"
console.log(name,age,height);
如果我们希望某个模块中所有的信息都导入,一个导入显然麻烦:
import * as info from './info.js'
console.log(info.name,info,age,info.height,info.friends);
Webpack是一个现代的JavaScript应用的静态模块打包
前端模块化
grunt/gulp的核心是Task
我们可以配置一系列的task ,并且定义task要处理的事务(例如ES6、ts转化、图片压缩、scss转化css),之后让grunt/gulp来一次执行这些task,并且让整个流程自动化,所以grunt/gulp也被称为前端自动化任务管理工具。
下面的task就是将src下面的所有js文件转成ES5的语法,并且最终输出到disk文件中
const gulp = require('gulp');
const babel = require('gulp-babel');
gulp.task('js',() =>
gulp.src('src/*js'))
.pipe(babel({
presets :['es2015']
}))
.pipe(gulp.dest('dist'))
);
grunt/gulp和webpack有什么不同
webpack模块化打包,webpack为了可以正常运行,必须依赖node环境,node为了可以正常的执行很多代码,必须其中各种依赖的包
npm工具(node packages manager)
安装webpack首先需要安装Node.js
node -v
全局安装webpack
npm install [email protected] -g
局部安装webpack
cd 对应目录
npm install [email protected] --save -dev
为什么全局安装后,还需要局部安装?
现在的js文件中使用了模块化的方式进行开发,他们不可以直接用,因为如果直接在index.html引入这两个js文件,浏览器并不识别其中的模块化代码。另外,在真实项目中当有许多这样的js文件时,我们一个个引用非常麻烦,并且后期非常不方便对他们进行管理。
我们可以使用webpack工具,对多个js文件进行打包,webpack就是一个模块化的打包工具,所以它支持我们代码中写模块化,可以对模块化的代码进行处理。另外,如果在处理完所有模块之间的关系后,将多个js打包到一个js文件中,引入时就变得非常方便了。
打包的命令
webpack src/main.js dist/bundle.js
使用打包后的文件
如果每次使用webpack的命令都需要写上入口和出口作为参数,就非常麻烦,webpack.config.js文件可以将这两个参数写到配置中,在运行时,可以直接读取。
const path = require('path')
module.exports = {
//入口:可以是字符串/数组/对象,这里我们数组只有一个,所以写一个字符串即可
entry:'./src/main.js',
//出口:通常是一个对象,里面至少包含两个重要属性,path 和 filename
output :{
path : path.resolve(__dirname,'dist'),//注意:path是一个绝对路径
filename : 'bundle.js'
}
}
package.json中定义启动
在终端执行的都是全局的
package.json中的scripts的脚本在执行时,会按照一定的顺序寻找命令对应的位置
{
"name": "meetwebpack",
"version": "1.0.0",
"description": "index.js",
"main": "webpack.config.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^3.6.0"
}
}
首先,会寻找本地的node_modules/.bin路径中对应的命令。
如果没有找到,会去全局的环境变量中去找
如何执行bulid指令
npm run bulid
loader是webpack中一个非常核心的概念
webpack的作用
load使用过程:
重新打包,会出现如下错误:
bundle.js 4.33 kB 0 [emitted] main
[0] ./src/main.js 299 bytes {0} [built]
[1] ./src/js/mathUtils.js 149 bytes {0} [built]
[2] ./src/js/info.js 81 bytes {0} [built]
[3] ./src/css/normal.css 623 bytes {0} [built] [failed] [1 error]
ERROR in ./src/css/normal.css
Module build failed: CssSyntaxError
(1:1) Unknown word
此处应该将webpack.config.js文件修改为
const path = require('path')//用node里面的,通过npm init
module.exports = {
entry: './src/main.js',
output: {
path : path.resolve(__dirname,'dist'),//绝对路径
filename:'bundle.js'
},
module: {
rules: [
{
test: /\.css$/,
//css-loader只负责将css文件进行加载
//style-loader 负责将样式添加到DOM中
//webpack在使用多个loader时,是从右向左的
use: ['style-loader','css-loader']
}
]
}
}
图片小于8kb
图片大于8kb
安装file-loader,运行成功,再次打包,就会发现dist文件夹下多了一个图片文件,这是webpack自动生成的名称,这是一个32位的hash值,目的是防止名称重复,但是,真实开发中,我们可能对打包的图片名字有一个的要求,比如,将所有的图片放在一个文件夹中,跟上图片原来的名称,同时也要防止重复,但是,我们发现图片并没有显示出来,这是因为图片使用的路径不正确,默认情况下,webpack会将生成的路径直接返回给使用者,但是我们整个程序是打包在dist文件夹下的,所以需要在路径下再添加一个dist/
我们可以在options中添加上如下选项
const path = require('path')//用node里面的,通过npm init
module.exports = {
entry: './src/main.js',
output: {
path : path.resolve(__dirname,'dist'),//绝对路径
filename:'bundle.js',
publicPath: 'dist/'
},
module: {
rules: [
{
test: /\.css$/,
//css-loader只负责将css文件进行加载
//style-loader 负责将样式添加到DOM中
//webpack在使用多个loader时,是从右向左的
use: ['style-loader','css-loader']
},
{
test: /\.less$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "less-loader" // compiles Less to CSS
}]
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'url-loader',
options: {
/*当加载的图片,小于limit时,会将图片编译成base64字符串形式*/
/*当加载的图片,大于limit时,需要使用file-load模块进行加载*/
limit: 73000,
name: 'img/[name].[hash:8].[ext]'
}
}
]
}
]
}
}
Webpack打包的js文件写的ES6语法并没有转成ES5,那么就意味着可能一些对ES6还不支持的浏览器没有办法很好的运行我们的代码
如果希望将ES6的语法转成ES5,那么就需要babel,而在webpack中,我们直接使用babel对应的loader就可以了。
npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
配置webpack.config.js
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
}
重新打包就可以
我们希望在项目中使用Vuejs,那么必然需要对其有依赖,所以需要先安装
注:后续是在实际项目中使用vue,所以并不是开始时依赖
npm install vue --save
Vue构建的两个版本
runtime-only
runtime-compiler
打包项目-错误信息
修改webpack的配置
resolve:{
alias:{
'vue$': 'vue/dist/vue.esm.js'
}
}
el和template区别
.vue文件封装处理
一个组件以一个js对象的形式进行组织和使用的时候是非常不方便的,一方面编写template模块非常的麻烦,另一方面如果有样式的话不知在哪里写合适,此时,我们以一种全新的方式来组织一个vue组件
安装vue-loader和vue-template-compiler
注:vue-template-compiler的版本必须与所安装的vue版本保持一致
npm install [email protected] [email protected] --save-dev --force
配置webpack.config.js文件
{
test :/\.vue$/,
use :['vue-loader']
}
plugin的定义
loader和plugin的区别
plugin的使用过程
添加版权的plugin
BannerPlugin,属于webpack自带的插件,为打包的文件添加版权声明
修改webpack.config.js文件:
const path = require('path')
const webpack = require('webpack')
module.exports = {
...
plugins: [
new webpack.BannerPlugin('最终版权归aaa所有')
]
}
重新打包程序:查看bundle.js文件的头部,可以看到
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xffscHno-1644828620589)(C:\Users\JMS\AppData\Roaming\Typora\typora-user-images\image-20220203152747651.png)]
打包html的plugin
目前,我们index.html存放在项目的根目录下的,我们知道,在真实发布项目时,发布的是dist文件夹中的内容,但是dist文件夹中如果没有index.html文件,那么打包的js等文件也没有意义了,所以我们需要将index.html文件打包到dist文件夹中,这个时候就可以使用HtmlWebpackPlugin插件
HtmlWebpackPlugin插件的作用
自动生成一个index.html文件(可以指定模板来生成),将打包的js文件,自动通过script标签插入到body中
安装HtmlWebpackPlugin插件
npm install [email protected] --save-dev --force
需要删除之前在output中添加的publicPath属性,否则插入的script标签中的src可能会有问题
js压缩的Plugin
在项目发布之前,我们必然需要对js等文件进行压缩处理,我们使用一个第三方的插件uglifyjs-webpack-plugin,并且版本号指定1.1.1,和CLI2保持一致
npm install [email protected] --save-dev
修改webpack.config.js文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3nJiRh8B-1644828620589)(C:\Users\JMS\AppData\Roaming\Typora\typora-user-images\image-20220204133632973.png)]
查看bundle.js,已经是被压缩过了的
webpack提供了一个可选的本地开发服务器,这个本地服务器基于node.js搭建,内部使用express框架,可以实现我们想要的让浏览器自动刷新显示我们修改后的结果,不过它是一个单独的模块,在webpack中使用之前需要先安装它
npm install --save-dev [email protected]
devserver也是作为webpack中的一个选项,选项本身可以设置如下属性:
webpack.config.js文件配置修改如下
我们可以再配置另外一个scripts:
webpack-配置文件的分离
npm install [email protected] --save-dev
如果只是简单写几个Vue的Demo程序,那么你不需要Vue CLI,如果你在开发大型项目,那么你需要,并且必然需要使用Vue CLI
使用Vue.js开发大型应用时,我们需要考虑代码目录结构、项目结构和部署、热加载、代码单元测试等事情。如果每个项目都要手动完成这些工作,那无疑效率比较低效,所以通常我们会使用一些脚手架工具来帮助完成这些事情。
CLI的定义
Vue CLI使用前提 -Node,Node环境要求8.9以上或者更高的版本
Vue CLI使用前提 -WebPack
安装Vue脚手架
npm install -g @vue/cli-init
注意:安装的是Vue CLI3的版本,如果需要按照Vue CLI2的方式初始化项目需拉取2.x模板
Vue CLI2初始化项目
vue init webpack my-project
Vue CLI3初始化项目
vue create my-project
runtime-compiler 和runtime-only的区别
createElement的使用
/* 1.普通用法: createElement('标签',{标签的属性},[''])
return createElement('h2',
{class: 'box'},
['Hello World', createElement('button', ['按钮'])])
} */
// 2.传入组件对象
return createElement(App)
Vue CLI3
箭头函数的基本使用
//箭头函数: 也是一种定义函数的方式
//1.定义函数的方式: function
const aaa = function () {
}
//2.对象字面量中定义函数
const obj = {
bbb: function () {
},
bbb(){
}
}
//3.ES6中的箭头函数
/* const ccc = (参数列表) =>{
}*/
//aaa用ccc表示
const ccc = () =>{
}
箭头函数的参数和返回值
//1.参数问题
//1.1放入两个参数
const sum =(num1, num2) =>{
return num1 + num2
}
//1.2放入一个参数
const power = num =>{
return num * num
}
//2.函数中的
//2.1函数代码块中有多行代码时
const test = () =>{
//1.打印Hello World
console.log("Hello World");
//2.打印Hello Vuejs
console.log("Hello Vuejs");
}
//2.1函数代码块中只有一行代码时
/* const mul = (num1, num2 ) => {
return num1 * num2
}*/
const mul = (num1, num2) => num1 * num2
/* const demo = () => {
console.log("Hello Demo");
}*/
const demo = () => console.log("Hello Demo")
console.log(demo());
箭头函数中this的使用
//当把一个函数作为参数传到另一个函数中的时候,用箭头参数较多
/* setTimeout(function (){
console.log(this)//window
},1000)*/
setTimeout(() => {
console.log(this)//window
},1000)
//结论: 箭头函数中的this引用的就是向外层作用域,一层层查找this,直到有this的定义
const obj = {
aaa() {
setTimeout(function () {
console.log(this);//window
})
setTimeout(()=>{
console.log(this);//obj对象
})
}
}
const obj = {
aaa() {
setTimeout(function () {
setTimeout(function () {
console.log(this);//window
})
setTimeout(() => {
console.log(this);//window
})
})
setTimeout(() => {
setTimeout(function () {
console.log(this);//window
})
setTimeout(() => {
console.log(this);//obj对象
})
})
}
}
早期的网站开发整个html页面是由服务器来渲染的,服务器直接生成渲染好对应的html页面,返回给客户端进行展示
一个页面有自己对应的网址,也就是url,url会发送到服务器,服务器会通过正则对该URL进行匹配,并且最后交给一个Controller进行处理,Controller进行各种处理,最终生成HTML或者数据,返回给前端,这就完成了一个IO操作
当我们页面中需要请求不同的路径内容时,交给服务器来进行处理,雾浮起渲染好整个页面,并且将页面返回给客户端,这种情况下渲染好的页面,不需要单独加载任何js和css,可以直接交给浏览器展示,这样也有利于SEO的优化。
后端渲染
后端路由
后端路由的缺点
随着Ajax的出现,有了前后端分离的 开发模式,后端只提供API来返回数据,前端通过Ajax获取数据,并且可以通过JavaScript将数据渲染到页面中,这样做最大的优点就是前后端责任的清晰,后端专注于数据上,前端专注于交互和可视化上。并且当移动端(ios/android)出现后,后端不需要进行任何处理,依然使用之前的一套API即可,目前很多的网站依然采用这种模式开发。
后端只负责提供数据,不负责任何阶段的内容
前端渲染
其实SPA最主要的特点就是在前后端分离的基础上加上了一层前端路由,也就是前端来维护一套路由规则。
SPA:simple page web application(单页面富应用),整个网页只有一个html页面
前端路由的核心:改变URL,但是页面不进行整体的刷新
修改url
location.hash = 'aaa'//修改url的hash值,不会重新请求数据
history.pushState({},'','home')//利用栈结构push,会保存历史记录
history.replaceState({},'','home')//只会替换,不会保存历史记录
history.go(-1) = history.back()//栈中弹出一个元素
history.go(1) = history.forward()//栈中压入一个元素
目前流行的三大框架,都有自己的路由实现
安装vue-router
npm install vue-router --save
在模块化工程中使用它(因为是一个插件,所以可以通过Vue.use()来安装路由功能)
使用vue-router的步骤
创建路由组件
配置路由映射:组件和路径映射关系
使用路由:
和
:该标签是一个vue-router中已经内置的组件,它会被渲染成一个标签。
:该标签会根据当前的路径,动态渲染出不同的组件,网页的其他内容,比如顶部的标题/导航,或者底部的一些版权信息等会和处于同一个等级,在路由切换时,切换的是挂载的组件,其他内容不会发生改变。
路由的默认路径
{
path: '',
redirect:'/home'
},
HTML5的history模式
改变路径的方式有两种:URL的hash和HTML5的history,默认情况下,路径的改变使用URL的hash
如果希望使用HTML5的history
const router = new Router({
//配置路由和组件之间的应用关系
routes,
mode: 'history'//将hash模式修改为html5中的history
})
router-link的其他属性
tag:tag可以指定渲染成什么组件
replace:replace不会留下history记录,所以指定replace的情况下,后退键返回不能返回到上一个页面
active-class:当对应的路由匹配成功时,会自动给当前元素设置一个router-link-active的class,设置active-class可以修改默认的名称,在进行高亮显示的导航菜单或者底部tabbar时,会使用到该类,但是通常不会修改类的属性,会直接使用默认的router-link-active即可
该class具体的名称也可以通过router实例的属性进行修改
const router = new Router({
//配置路由和组件之间的应用关系
routes,
mode: 'history',//将hash模式修改为html5中的history
linkActiveClass: 'active'
})
路由代码跳转
在某些情况下,一个页面的path路径可能是不确定的,比如我们进入用户界面时,希望是如下路径
除了有前面的/user之外,后面还跟上了用户的ID,这种path和Component的匹配关系,我们称之为动态路由(也是路由传递数据的一种方式)。
当打包构建应用时,Javascript包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
路由中通常会定义很多不同的页面,一般情况下,是放在一个js文件中,但是,页面这么多放在一个js文件中,必然会造成这个页面非常大。如果我们一次性从服务器请求下来这个页面,可能需要花费一定的时间,甚至用户的电脑上还出现了短暂空白的情况,为了避免这种情况,使用路由懒加载。
路由加载的主要作用就是将路由对应的组件打包成一个个js代码块。只有在这个路由被访问到的时候,才加载对应的组件。
懒加载的方式
在ES6中,有更加简单的写法来组织Vue一步组件和Webpack的代码分割
const Home = () => import('../components/Home.vue')
路由嵌套
标签传递参数的方式
传递参数主要有两种类型: params和query
params的类型
query的类型(传递大量数据时使用)
URL: 协议://主机:端口/路径?查询
scheme://host:port/path?query#fragment
index.jsp
配置meta
path: '/about',//about 前端路由地址
component: About,
meta: {
title: '关于'
}
添加beforeEach/afterEach方法
//全局守卫,除了全局守卫之外,还有路由独享的守卫,组件内的守卫
//前置守卫(guard)是在跳转前回调的
router.beforeEach((to, from , next ) => {
//从from跳到to
document.title = to.matched[0].meta.title;
console.log(to);
next();
})
//后置钩子(hook)是在跳转后回调的,不需要调用next()函数
router.afterEach((to , from ) => {
})
meta: 描述数据的数据
keep-alive
keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染
include -字符串或正则表达,只有匹配的组件会被缓存
exclude-字符串或正则表达式,任何匹配的组件都不会被缓存
//,前后不能加空格,正如正则表达式也不能随便加空格
router-view 也是一个组件,如果直接被包在keep-alive里面,所有路径匹配到的视图组件都会被缓存
activated和deactived两个生命周期,只有该组件被保持了状态使用了keep-alive时,才是有效的