前端小白简单总结,参考黑马珠峰等课程以及其他内容整合,还望各位大佬多多指教~
Vue基础
零、Vue前置知识:es6部分内容
一、Vue初识
- vue数据驱动(主要操作的是数据)
- js、jQuery都是操作dom,导致页面重复渲染
框架和库
- 框架:vue 拥有完整的解决方案,我们写好人家调用我
- 库:jquery underscore zepto animate.css 我们调用他
1、Vue简介
因为Object.defineProperty(es5)的没有替代方案,所以不支持ie8以下版本
Vue.js(读音 /vju:/,类似于view) 是一套构建用户界面的渐进式(渐近增强)框架,它只关注视图层。
- 声明式渲染(无需关心如何实现)
- 组件系统
- 客户端路由(vue-router)
- 集中式状态管理(vuex)
- 项目构建(vue-cli)
2、优点:
- 易用:熟悉HTML、CSS、JavaScript知识后,可快速上手Vue
- 灵活:在一个库和一套完整框架之间自如伸缩
- 高效:20kB运行大小,超快虚拟DOM
3、主要开发思想
- 组件化开发:
把页面拆分成多个组件,ui页面映射为组件树,每个组件依赖的模板(html) css、js等资源放在一起开发、维护和测试 - 响应的数据变化(数据驱动视图):
当数据发生改变时 -> 视图随之发生改变
4、Vue基本使用
1) Vue使用的基本步骤
1> 需要提供标签用于填充数据
2> 引入vue.js库文件
3> 可以使用vue的语法做功能了
4> 把vue提供的数据填充到标签里面
2) Hello World实例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World</title>
</head>
<body>
<div id="app">
<div>{{msg}}</div>
<div>{{1+1}}</div>
<div>{{msg+'-----'+123}}</div>
</div>
<script src="js/vue.js"></script>
<script>
// 引入vue会给你一个Vue构造函数
var vm = new Vue({ // vm = viewModel
el: '#app', // 告诉vue能管理哪个部分,querySelector
data: { // data中的数据会被vm所代理
msg: 'Hello World' // 可以通过vm.msg取到对应的内容
}
}) // Object.defineProperty
</script>
</body>
</html>
1、实例参数分析:
2、差值表达式用法:
-#### 将数据填充到HTML标签中
-#### 差值表达式支持基本的计算操作
5、Vue代码运行原理分析
概述编译过程的概念(Vue语法—>原生语法)
5、Vue环境搭建(Vue-cli脚手架)
二、Vue的模板语法
1、前端渲染
1) 定义:把数据填充到HTML标签中
2) 前端渲染方式
- 原生js拼接字符串
- 使用前端模板引擎
- 使用vue特有的模板语法
3)模板语法概览:
2、差值表达式(moustache 小胡子语法)
<div>{{ msg }}</div>
<div>{{ 1+1 }}</div>
<div>{{ msg+'-----'+123 }}</div>
3、指令(dom元素的行间属性)
1)定义:
vue的指令directive只是dom上的行间属性,vue给这类属性赋予
一定的意义,来实现特殊的功能,所有指令都以v-开头,value属
性默认情况下,vue会忽略掉 selected checked都没有意义
2)v-cloak指令
“闪动”产生原因:Vue解析差值表达式是先将差值表达式显示在页面中,然后迅速替换为对应的内容;
原理:先通过样式隐藏内容,然后在内存中进行值的替换,替换好之后再显示最终的结果;
3)数据绑定指令
特点:相比差值表达式更加简洁,没有“闪动”问题
1、存在安全问题
2、本网站内部数据可以使用,来自第三方的数据不可以用
3、重复渲染,影响性能
1、显示原始信息,跳过编译过程
4)数据响应式
1> 如何理解数据响应式
1、html5中的响应式:屏幕尺寸变化导致样式的变化
2、数据的响应式:数据的变化导致页面内容的变化
2> 数据绑定:将数据填充到标签中
3> v-once:只编译一次,
1、显示内容之后不再具有响应式功能
2、应用场景:如果显示的信息后续不需要再修改,这样可以提高性能
5)自定义指令:directive:用来操作dom
<button v-color="flag">变色</button>
<div v-drag></div>
<script>
let vm = new Vue({
directives: {
color(el, bindings){ // el指代的是当前操作的dom,当前是指button按钮
el.style.background = bindings.value
},
drag(el){
el.onmousedown = function(e){
var disx = e.pageX - el.offsetLeft;
var disy = e.pageY - el.offsetTop;
document.onmousemove = function(e){
el.style.left = e.pageX - disx + 'px';
el.style.top = e.pageY - disy + 'px';
}
document.onmouseup = function(){
document.onmousemove = document.onmouse = null
}
e.preventDefault();
}
}
}
})
</script>
4、双向数据绑定
1)数据变化会导致显示发生变化
2)修改页面内容导致数据发生变化
vue会循环data中的数据(数据劫持),依次的增加getter和setter
使用变量时,先要初始化,否则新加的属性不会导致页面刷新
给对象添加响应式的数据变化有三种方法:
1> 变量初始化
2> 使用setter添加属性:vm.$set(vm.a, ‘school’, 1) // 此方法可以给对象添加响应式的数据变化
3> 替换原对象:vm.a = {school: ‘1’}
要想改变数组的某一项(重点)
data: {
arr: [1, 2, 3, 4, 5]
}
错误:
vm.arr[0] = 100; // 去改变数组中的某一项是监控不到的
vm.arr.length -=2; // 也不能使用改变数组长度的方法
只能使用变异方法:
pop push shift unshift sort reverse splice
或filter map
vm.arr = vm.arr.map(item=>item*=3);
// v-model会将msg的值赋予输入框,输入框的值改变了会影响数据
<input type="text" v-model="uname" />
数据双向绑定的简单原理实现:(Object.defineProperty)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="text" id="input">
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let obj = {};
// Object.defineProperty(obj, 'name', {
// configurable: false, // 是否可配置(删除)
// writable: false, // 是否可重新赋值
// enumerable: false, // 是否可枚举
// value: 1
// })
// delete obj.name
// obj.name = 1000
// for(key in obj){
// console.log(key)
// }
Object.defineProperty(obj, 'name', {
get(){ // 取obj的name属性会触发
return temp['name']
},
set(val){// 给obj赋值会触发set方法
console.log(val);
// obj.name = val; // 会反复调用set,造成死循环
temp['name'] = val; // 改变temp的结果
input.value = val; // 将值赋予输入框
}
});
input.value = obj.name; // 页面一加载时,会调用get方法
input.addEventListener('input', function () { // 等待输入框的变化
obj.name = this.value; // 当值变化时会调用set方法
})
</script>
</body>
</html>
多用于表单元素,忽略value, checked, selected,将数据绑定到视图上,视图修改后会影响数据的变化
如果是复选框,只有一个复选框的时候,会把此值转化为boolean类型,如果true则代表选中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h1>{{ title }}</h1>
爱好: <input type="checkbox" v-model="a" />跑步
{{ a }}
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
title: 'checkbox demo',
a: ''
}
})
</script>
</body>
</html>
结果如图:
如果是多个checkbox,要增加value属性并且数据类型是数组
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h1>{{ title }}</h1>
爱好: <input type="checkbox" v-model="a" value="跑步"/>跑步
<input type="checkbox" v-model="a" value="骑行"/>骑行
<input type="checkbox" v-model="a" value="游泳"/>游泳
{{ a }}
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
title: 'checkbox demo',
a: []
}
})
</script>
</body>
</html>
结果如图:
下拉框select也是同理:
原生js实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>原生js实现下拉框</title>
</head>
<body>
<select id="select">
<option value="跑步">跑步</option>
<option value="骑行">骑行</option>
<option value="游泳">游泳</option>
</select>
</body>
<script>
let oSelect = document.getElementById('select');
oSelect.onchange = function (){
console.log(this.value)
}
</script>
</html>
vue方式实现:
如果select是多选框,数据类型要是数组
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h1>{{ title }}</h1>
<select>
<option value="" disabled multiple>请选择</option>
<option value="跑步">跑步</option>
<option value="骑行">骑行</option>
<option value="游泳">游泳</option>
</select>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
title: 'select demo',
a: []
}
})
</script>
</body>
</html>
单选框radio同理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h1>{{ title }}</h1>
<input type="radio" v-model="gender" value="男" />男
<input type="radio" v-model="gender" value="女" />女 {{ gender }}
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
title: 'select demo',
gender: '男'
}
})
</script>
</body>
</html>
MVC设计思想(backbone、或者结合后端)单向
- M:model数据
- V: view视图
- C: controller 控制器
MVVM设计思想(angular, vue)双向
- M(model)
- V(view)
- VM(View-Model)
5、事件绑定
原生js事件绑定:
<div onclick="fn()" id="btn">点击</div>
<script>
function fn() {
alert(1);
}
console.log(btn.onclick); // onclick(event){fn}
</script>
v-on: 在dom节点上绑定一个事件,简写为@
1)事件绑定方式
1> 直接绑定函数名称
<button @click="hello">hello1<button>
2> 调用函数
<button @click="hello()">hello2<button>
3> 普通参数和事件对象
如果不传递参数,则不要写括号会自动传入事件源$event,如果写括号了要手动传入$event属性
// 如果事件绑定函数调用,事件对象必须作为最后一个参数显示传递,并且名称必须是$event
<button @click="hello("hi", $event)">hello3<button>
2)常用事件修饰符(连写会有先后顺序)
原生js方式:event.stopPropagation();
<a v-on:click.stop="handle">跳转</a>
原生js方式:event.preventDefault();
<a v-on:click.prevent="handle">跳转</a>
3)常用按键修饰符
<input v-on:keyup.enter="submit">
<input v-on:keyup.delete="handle">
4)自定义按键修饰符
// 名是自定义的,但是对应的值必须是按键对应event
Vue.config.keyCodes.f12 = 65
6、属性绑定
1)动态处理属性
<a v-bind:href="url">跳转</a>
<a:href="url">跳转</a>
2)v-model的底层实现原理分析(有面试问过)
用v-bind绑定一个属性msg,用v-on绑定一个事件,事件中将msg的值替换为当前input的值。
<input v-bind:value="msg" v-on:input="msg=$event.target.value">
7、样式绑定
1)class样式处理
<div v-bind:class="{ active: isActive }"></div>
<div v-bind:class="[ activeClass, errorClass ]"></div>
1> 对象绑定和数组绑定可以结合使用
<div v-bind:class="[ activeClass, errorClass, {test: isTest} ]"></div>
data:{
activeClass: 'active',
errorClass: 'error',
isTest: true
}
2> class绑定的值可以简化操作
<div v-bind:class="arrClasses"></div>
<div v-bind:class="objClasses"></div>
data:{
activeClass: 'active',
errorClass: 'error',
arrClasses: ['active', 'error'],
objClasses: {
active: true,
error: true
}
}
3> 默认的class会保留
<div class="base" v-bind:class="objClasses"></div>
data:{
objClasses: {
active: true,
error: true
}
}
2)style样式处理
<div v-bind:style="{ color:activeColor, fontSize: fontSize }"></div>
data:{
activeColor: '#ccc',
fontSize: 12px
}
可简化为:
<div v-bind:style="objStyles"></div>
data:{
objStyles:{
activeColor: '#ccc',
fontSize: 12px
}
}
<div v-bind:style="[baseStyles, overridingStyles]"></div>
8、分支循环结构
1)分支结构
<div v-if="score>=90">优秀</div>
<div v-else-if="score<90&&score>=80">良好</div>
<div v-else-if="score>=70&&score>=60">一般</div>
<div v-else>比较差</div>
data:{
score: 80
}
}
<div v-show>测试v-show</div>
2)v-if与v-show的区别(性能考虑推荐v-show)
-
v-if控制元素是否渲染到页面(操作的是dom,控制dom节点是否显示)
-
v-show控制元素是否显示(操作的是样式,已经渲染到了页面,改变display属性)
-
如果频繁的切换dom,使用v-show,当数据一开始就确定下来使用v-if,如果if不通过内部指令不会再执行了
使用样例:
<template>
<div class="hello">
<h1 v-cloak>{{ msg }}</h1>
<h2 v-html="xx"></h2>
<h2 v-show="isTrue">v-show指令</h2>
<h2 v-if="isTrue">v-if指令</h2>
<input v-on:click="fnxx" type="button" value="显示/隐藏" />
</div>
</template>
<script>
export default {
name: 'HelloWorld',
// 模型数据方法:返回值是一个对象
data () {
return {
msg: '是日前端',
xx: '日拱一卒',
isTrue: false
}
},
methods: {
fnxx(){
// methods中定义的函数,里面的this指向的是当前的vue实例
// 简单方式
this.isTrue = !this.isTrue;
// if(this.isTrue == false){
// this.isTrue=true;
// }else{
// this.isTrue=false;
// }
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
结果如图:
3)循环结构
原生js中是用innerHtml拼字符串
v-for(解决循环问题的,更高效,会复用原有的结构)
使用:要循环谁就在谁的身上增加v-for属性
<li v-for="item in list"> {{item}} </li>
<li v-for="(item, index) in list">{{ item }} + "---" + {{index}} </li>
data:{
item: [1, 2, 3, 4, 5, 6]
}
}
<li :key="index" v-for="(item, index) in list">
<span> {{item.ename}} </span>
<span> {{item.cname}} </span>
</li>
data:{
item: [{
ename: 'apple',
cname: '苹果'
},{
ename: 'orange',
cname: '橘子'
},{
ename: 'pear',
cname: '梨子'
}]
}
}
<li :key="item.id" v-for="(item, index) in list">{{ item }} + "---" + {{index}} </li>
var obj ={
uname: 'Mickey',
age: '6',
gender: 'female'
}
for(var key in obj){
console.log(key, obj[key]);
}
<div v-for="(value, key, index) in object"></div>
<div v-if="value==12" v-for="(value, key, index) in object"></div>
注意:methods和data中的数据会全部放到vm上,而且名字不能冲突,冲突会报错,methods中的this指向的都是vue实例。
案例:简易Todo List实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Todo List</title>
</head>
<body>
<div id="app">
<h1>{{ title }}</h1>
<input type="text" v-model="todo" @keyup.enter="add"/>
<ul>
<li v-for="(item, index) in list">{{ item }} <button @click="del(index)">删除</button></li>
</ul>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data:{
title: 'Todo List',
todo: "",
list: []
},
methods: {
add(){
console.log(this.todo)
this.list.push(this.todo)
console.log(this.list)
this.todo = ''
},
del(i){
console.log(this.todo)
this.list = this.list.filter((item, index) => index !== i)
}
}
})
</script>
</body>
</html>
结果如图:
三、过滤器
原数据不变的情况下,只是改变显示的效果,利用管道符|实现
<!-- 过滤器 原数据不变的情况下,只是改变显示的效果 管道符号 -->
<div>{{ product.product * productPrice | toFixed(2) }}</div>
filters: [{
toFixed(input, param1){
return '¥' + input.toFixed(param1); // input代表的是管道符前面的内容,param1代表的是toFixed中传递的参数
}
}]
四、computed计算属性(不是方法)
表达式的计算逻辑可能会比较复杂,使用计算属性可以使模板内容更加简洁
两部分组成有get和set(不能只写set)一般情况下,通过js赋值影响其他人或者表单元素设置值的时候会调用set方法
computed默认调用get方法,必须要有return,computed不支持异步
<div id="app">
全选 <input type="checkbox" v-model="checkAll"></input><br>
<input type="checkbox" v-for="product in products" v-model="product.isSelected">
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
// 当给全选赋值时,要影响其他人的变化,当页面刷新时,获取全选值,是根据下面的checkbox计算出来的结果给全选赋值
computed: { // 放在computed中最后也会放在vm上,不能和methods与data相同
checkAll: {
// 当products值变化时会重新计算
get(){ // 返回什么结果,就会赋予给checkAll属性
// get和set中,this指向实例 默认v-model会获取checkAll的值,所以会调用get方法
return this.products.every((item=>item.isSelected);)
},
set(val){ // 当我们给checkbox赋值的时候
this.products.forEach(p=>p.isSelected = val);
}
},
sum(){ // 如果计算属性写成函数,默认调用的就是get方法
// sum的结果会缓存,如果依赖的数据没有变化就不会重新执行
return this.products.reduce((prev, next)=>{
if(!next.isSelected)
return prev;
return prev + next.productPrice * next.productCount;
}, 0);
}
}
})
</script>
<div id="app">
<input type="text" v-model="a">
{{ msg }}
<!-- 根据输入框中的内容,算出一个错误信息 -->
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {a: '',
msg: ''},
computed: { // computed默认调用get方法,必须要有return,computed不支持异步
msg(){
if(this.a.length < 3){
return '少了'
}
if(this.a.length > 6){
return '多了'
}
return '';
}
}
</script>
计算属性和methods的区别:计算属性是基于它们的依赖(归vue管理的数据,可以响应式变化的)属性进行缓存的,方法不存在缓存。
五、侦听器watch
只有值变化的时候才会触发,支持异步,当需要在数据变化时执行异步或开销较大的操作时一般使用,其他情况下我们更善于使用
computed
<div id="app">
<input type="text" v-model="a">
{{ msg }}
<!-- 根据输入框中的内容,算出一个错误信息 -->
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {a: '', msg: ''},
watch: { // 只有值变化的时候才会触发,支持异步,其他情况下我们更善于使用computed
a(newVal, oldVal){ // watch的属性名要和观察的对象的名字一致
if(newVal.length < 3){
return this.msg = '太少'
}
if(newVal.length > 6){
return this.msg = '太多'
}
this.msg = '';
}
}
})
</script>
created(){ //
// 如果localStorage中有数据就用,没有就用默认的
this.todos = JSON.parse(localStorage.getItem('data')) || this.todos;
}
watch:{
todos: {
handler(){ // 默认写成函数,就相当于默认写了个handler
// localStorage默认存的是字符串
localStorage.setItem('data', JSON.stringify(this.todos))
}, deep: true
}
}
六、路由
- 访问不同的路径,就可以返回不同的结果
- 多页面(spa)
- single page application
- hash方式(开发环境):通过hash记录跳转的路径(可以产生历史管理),不支持seo
- history方式(生产环境): 浏览器自带的历史管理办法history(history.pushState( ))可能会导致404错误
七、Vue生命周期钩子函数以及实例上的属性和方法
八、组件化开发
参见:Vue组件化开发简单总结
九、Vue组件间通信
参见:Vue组件间通信简单总结
十、axios的使用
十一、vuex
参见:Vuex简单总结