一、Vue入门案例
VUE 是一个渐进式框架 分布式应用思想
实现步骤:
1.定义Vue的公共区域
2.导入函数类库
3.实例化Vue对象
4.数据引用 使用插值表达式
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>入门案例</title>
</head>
<body>
<!-- 1.定义vue工作的区域 -->
<div id="app">
<h1>vue的入门案例</h1>
<!-- 4数据的引用 插值表达式-->
{{hello}}
</div>
<!-- 2.导入函数类库 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<!-- 3.实列化vue对象 -->
<script>
const app=new Vue({
//关键字el:标识vue对哪个元素有效
el: "#app",
data: {
hello:"你好Vue"
}
});
</script>
</body>
</html>
二、常用指令
1 v-cloak
当浏览器解析js完成前,用户看的数据是插值表达式比如 {{msg}},直到浏览器加载完成全部js,则插值表达式{{msg}}替换为具体的数据,不想让用户看到没有解析的数据,使用v-cloak属性
2 v-text
v-cloak写着繁琐,还需要设置样式display: none; 将上述v-cloak优化啦
<h1 v-text="msg"></h1>
3 v-html
动态的展现html标签 让浏览器解析html之后展现
<span v-html="html"></span>
4 v-pre
只想展现插值表达式,比如 {{msg}},不需要vue解析
语法:v-pre vue直接跳过该标签不解析
<span v-pre>{{msg}}</span>
5 v-once
元素只解析一次,之后用户随意修改,数据不变
<span v-once>{{one}}</span>
6 v-model
双向数据绑定,只能标识可编辑的标签(input ,textarea,select.radio,checkbox)
数据绑定:
1.页面与数据绑定 数据变化 则页面数据同步修改
2.数据与页面绑定 页面值发生变化,则数据同步修改
<input type="text" v-model="msg"/>
属性说明:
1. number 将用户输入变为数值类型
2. trim 去掉开头和结尾的空格
3. lazy 懒加载 当鼠标离焦时生效
<input type="" name="age" v-model.number="age" />
<button type="button" @click="expand">增加10倍</button>
<input type="" name="name" v-model.trim="name" />
获取name属性的长度{{name.length}}<br>
<input type="" name="username" v-model.lazy="username" />观察响应现象{{username}}
7 v-on
事件绑定,v-on: 可以简写为@,可以直接编辑操作内容,也可以通过方法操作
<button type="button" v-on:click="num++">增加1</button>
<!-- 1.2 v-on 简化操作@ -->
<button type="button" @click="num++">增加1</button>
<!-- 1.3 通过方法实现新增 -->
<button type="button" @click="addNum">增加1</button>
8 v-bind
属性绑定 v-bind:属性=“数据的key” 可以简写为 :属性=“数据的key”
6 :class
类型绑定
<!-- 类型绑定 一般的class用来修饰样式
需求:这个样式有时需要,有时不需要
:class="{类型名称:boolean类型数据}"
true:样式绑定正常
false:不绑定样式
-->
<div :class="{redClass:flag}"></div>
<div :class="myClass"></div>
<button type="button" @click="flag=!flag">切换样式</button>
三、修饰符
1 事件访问修饰符
stop 阻止事件冒泡
事件冒泡:由于嵌套关系,先执行内部事件,如果执行成功后,则事件冒泡给外层事件
prevent 阻止默认行为
2 按键访问修饰符
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>按键访问修饰符</title>
</head>
<body>
<div id="app">
<!-- 1.按键访问修饰符 回车触发
keyup:键位弹起 常用的
keydown:键位按下
keypress:数字键盘
-->
回车触发 <input type="text" @keyup.enter="enter" />
空格按下触发 <input type="text" @keydown.space="enter" />
按键触发 <input type="text" @keyup.delete="enter" />
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
const app = new Vue({
el: '#app',
data: {
},
//定义vue对象中的方法
methods: {
enter(){
alert("回车触发")
}
}
})
</script>
</body>
</html>
四、结构
1 分支结构
语法:
1.v-if 如果满足条件展现后续内容
2.v-else-if 除了if之外的其它的可能
3.v-else 上述条件都不满足时 展现如下内容
注意事项:
1.v-if 可以单独编辑
2.v-else/v-else-if 不可以单独使用必须与v-if使用
录入成绩 <input v-model="score" />
<h1>考试成绩</h1>
<div v-if="score>=90">优秀</div>
<div v-else-if="score>=80">良好</div>
<div v-else-if="score>=70">中等</div>
<div v-else-if="score>=60">及格</div>
<div v-else>再接再厉,你是最棒的</div>
2 循环结构
问题:什么样的数据需要循环 1.数组 2.对象
语法:v-for 遍历展现的是标签 v-for=“遍历后的元素 in 集合数据”
<body>
<!-- 1.定义vue工作的区域 -->
<div id="app">
<!-- 问题:什么样的数据需要循环 1.数组 2.对象
语法:v-for 遍历展现的是标签 v-for="遍历后的元素 in 集合数据"
-->
<h1>遍历数组</h1>
<p v-for="item in hobby" >{{item}}</p>
<p v-for="item in hobby" v-text="item"></p>
<hr >
<h1>遍历对象</h1>
1.如果直接遍历对象,则展现value的值
<p v-for="item in user" v-text="item"></p>
2.如果直接遍历对象 arg1:value arg2:key
<div v-for="(value,key) in user">
<p>{{key}}:{{value}}</p>
</div>
3.如果直接遍历对象 arg1:value arg2:key args:index
<div v-for="(value,key,index) in user">
<p>{{index+1}}. {{key}}:{{value}}</p>
</div>
<hr >
4.遍历集合
<!-- 约定: :key 用来区分遍历的节点信息 -->
<div v-for="user in userList" :key="user.id">
<p>ID编号:{{user.id}} ,名称:{{user.name}}</p>
</div>
</div>
<!-- 2.导入函数类库 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<!-- 3.实列化vue对象 -->
<script>
const app=new Vue({
//关键字el:标识vue对哪个元素有效
el: "#app",
data: {
hobby: ['电脑','手机','平板'],
user: {
id: 100,
name: 'tomcat猫'
},
userList:[
{id:100,name:"tomcat猫1"},
{id:200,name:"tomcat猫2"},
{id:300,name:"tomcat猫3"},
]
},
methods:{
}
});
</script>
</body>
五、计算属性
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>计算属性</title>
</head>
<body>
<!-- 1.定义vue工作的区域 -->
<div id="app">
<!-- 需求:将数据字母进行反转abc 反转之后cba
方法:将数据拆分为数组,将数组进行反转,在将数组合并为字符串
函数:1.split 拆分 2.reverse 反转数据 3.join('')将数组转换为字符串
-->
用户输入: <input v-model="msg"/><br>
数据展现: {{msg.split("").reverse().join("")}}<br>
<!-- 计算属性用法:将需要计算的操作通过特定的方法先行计算,之后将结果进行展现
使用场景:如果数据需要大量计算 可以使用计算属性实现
-->
计算属性:{{reverse}}
<hr >
<!-- 面试题;计算属性与方法的区别
计算属性如果调用多次,则有缓存的机制,只计算一次
方法调用没有缓存机制,所以调用多次,则计算多次
如果一个计算重复调用时首选计算属性
-->
{{reverse}}{{reverse}}<br>
{{reverseMe2()}}{{reverseMe2()}}
<!-- <button type="button" @click="reverseMe">调用方法</button> -->
</div>
<!-- 2.导入函数类库 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<!-- 3.实列化vue对象 -->
<script>
const app=new Vue({
//关键字el:标识vue对哪个元素有效
el: "#app",
data: {
msg: 'absdefg'
},
methods:{
reverseMe2(){
console.log("方法执行")
this.msg.split("").reverse().join("");
}
},
//定义计算属性
computed:{
//定义一个方法,要求必须有返回值!!!
reverse(){
console.log("计算属性执行")
return this.msg.split("").reverse().join("");
}
}
});
</script>
</body>
</html>
六、Vue的生命周期
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试vue生命周期函数</title>
</head>
<body>
<!-- 钩子函数:整个vue有一个完整的执行过程,如果用户需要对vue对象进行额外的拓展,可以采用预留的“接口”进行拓展,
我们把项目中提前设定好的“接口”,在js中称之为钩子函数
-->
<!-- 总结:
1.钩子函数作用:对原有的操作进行扩展:8个,初始化函数4个,修改函数2个,销毁函数2个
2.mounted()函数标识vue对象实列化成功
3.生命周期函数是vue对象独有的内容 注意写法不要放到methods中
-->
<div id="app">
<h3 v-text="msg"></h3>
<button @click="destroy">销毁</button>
</div>
<!--引入js函数类库 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
const app = new Vue({
el : "#app",
data : {
msg: "vue生命周期"
},
//在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
beforeCreate(){
console.log("beforeCreate")
},
//在实例创建完成后被立即调用
created(){
console.log("created")
},
//在挂载开始之前被调用:相关的 render 函数首次被调用。
beforeMount(){
console.log("beforeMount")
},
//实例被挂载后调用,这时 el 被新创建的 vm.$el 替换了。
mounted(){
console.log("mounted")
},
//数据更新时调用,发生在虚拟 DOM 打补丁之前
beforeUpdate(){
console.log("beforeUpdate")
},
//由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
updated(){
console.log("updated")
},
//实例销毁之前调用。在这一步,实例仍然完全可用
beforeDestroy(){
console.log("beforeDestroy")
},
//实例销毁后调用。
destroyed(){
console.log("destroyed")
},
methods:{
destroy(){
this.$destroy()
}
}
})
</script>
</body>
</html>
七、数组的操作
数组相关用法 队列/栈 push 压栈 pop 弹栈
push() 在最后追加元素
pop() 从最后删除元素
shift() 从开头删除元素
unshift() 从开头追加元素
sort() 排序 按照字符编码编码顺序排列
reverse() 数组反转
splice(arg1,arg2,arg3) 替换/删除数据
arg1: 操作数据的起始位置 下标从0开始
arg2:操作的数量
arg3:替换后的值,可以有多个值,一个值替换一个,多个值替换多个;也可以没有值,代表删除
八、axios
1.promise对象解决传统ajax中的回调地狱问题
2.Axios封装了promise对象,异步调用更加简洁
3.常见请求类型1.get(查) 2.post(新增) 3.put(改) 4.delete(删除)
4.分组:用法相同get/delete post/put
注意事项:默认条件下通过浏览器只能发起get请求
RestFul主要目的是简化get请求的方式,将原有的字符串的拼接改为使用"/"的方式进行参数传递
例子:
1.get请求类型 http://localhost:8090/getUser?name=大乔&age=18
2.restFul请求类型 http://localhost:8090/getUser/大乔/18
注意事项
1.利用restFul可以简化用户get请求的类型
2.编辑restFul请求时,应该采用"无状态(请求中不能出现动词)"的请求名称
3.使用restFul时 应该按照规范编辑请求的类型GET(查) PUT(修改) POST(新增) DELETE(删除)
1 入门案例
axios.get("http://localhost:8090/findAll")
.then(function(result){
//result返回值是一个promise对象,动态获取服务器返回值使用result.data的方式
console.log(result.data);
});
axios.get("http://localhost:8090/getUserByNs",{
//关键字params
arams: user
}).then(result => {
console.log(result.data)
})
2 回调地狱解决
<body>
<h1>axios回调地狱</h1>
<script src="../js/axios.js"></script>
<script type="text/javascript">
let ajaxA= axios.get("http://localhost:8090/getA");
function ajaxB(str){
//返回promise对象
return axios.get("http://localhost:8090/getB",{
params: {
str:str
}
})
}
function ajaxC(str){
return axios.get("http://localhost:8090/getC",{
params: {str: str}
})
}
ajaxA.then(result => {
return ajaxB(result.data)
}).then(result =>{
return ajaxC(result.data)
}).then(result =>{
alert(result.data);
})
</script>
</body>
3 axios简化操作
- 设定公共的请求路径
axios.defaults.baseURL = "http://localhost:8090";
2.解构赋值
想法:能否利用一个方法,就将数据直接获取,简化2步调用的结构
实现:ES7 提供了await、 async 简化现有axios操作
用法说明:
1. await 标识异步请求,解构操作
2. async 用在函数中,支持解构 要求同时出现
语法结构:
let {} 用来接收解构后的对象
//定义一个函数
async function ajax() {
//语法结构:将ajax返回值data赋值给value
//let obj = await axios.post("/saveUser", user) obj就是原来的回调函数result
let {data: value} = await axios.post("/saveUser", user)
console.log(value);
}
九、组件
1 组件化思想
组件系统是 Vue 的一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树.
使用组件可以将一些重复的内容进行封装.各个组件单独维护.体现了分治的思想(分布式思想)
补充知识: 为了保证组件化 相互之间互不干扰,则应该在组件内部 单独定义html/js/css.
2 全局组件
步骤
1.组件中的data 是一个函数() 必须有返回值.
2.组件的模版必须有一个根目录.
3.如果组件的名称采用驼峰规则的命名,则标签引用时需要使用-线进行关联.
入门案例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>全局组件定义</title>
</head>
<body>
<div id="app">
<!-- 2.3 引用组件 通过标签 页面html解析标签后都变成小写字母,如果使用驼峰规则使用-线连接 -->
<add-num-com></add-num-com>
<add-num-com></add-num-com>
</div>
<hr>
<div id="app2">
我是app2,另一个Vue对象
<add-num-com></add-num-com>
</div>
<!-- 2.2定义模版html 要求模版必须有根目录-->
<template id="addNumTem">
<div>
<h3>测试组件用法</h3>
数据: {{num}}
<button @click="addNum">自增</button>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
//2.定义全局组件
Vue.component("addNumCom", {
//2.1定义属性
data() {
return {
num: 1
}
},
//2.2 定义组件模版 编辑html/js/css
template: "#addNumTem",
methods: {
addNum() {
this.num++;
}
}
});
//1.定义vue对象
const app = new Vue({
el: "#app"
})
//2.定义第二个vue对象
const app2 = new Vue({
el: '#app2'
})
</script>
</body>
</html>
tips: 组件定义在未来由前端框架node.js提供的脚手架完成. 现阶段主要学习组件中语法结构
掌握: data 数据的写法, template 注意事项, methods写法.
3 局部组件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>局部组件定义</title>
</head>
<body>
<div id="app">
<!-- 局部组件使用 -->
<hello1></hello1>
</div>
<div id="app2">
<!-- 测试局部组件的作用域,不能直接调用 -->
<hello1></hello1>
</div>
<!-- 3.定义模版标签 -->
<template id="hello1Tem">
<div>
<h3>我是局部组件A</h3>
数据: {{msg}}
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
//2.定义局部组件实体
let hello1 = {
//2.1定义属性
data() {
return {
msg: "我是组件A~hello1"
}
},
template: "#hello1Tem"
}
//1.定义vue对象
const app = new Vue({
el: '#app',
//在app对象内部定义局部组件,只能在app对象内部使用
components: {
//定义组件的名称:定义组件内容,内容是引用(引用上面定义的)
//hello1: hello1
hello1
//k-v 字符相同 只写一个
}
})
//定义第二个vue对象
const app2 = new Vue({
el: "#app2"
})
</script>
</body>
</html>
十、路由机制
1 VUE Router介绍
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:
嵌套的路由/视图表
模块化的、基于组件的路由配置
路由参数、查询、通配符
基于 Vue.js 过渡系统的视图过渡效果
细粒度的导航控制
带有自动激活的 CSS class 的链接
HTML5 历史模式或 hash 模式,在 IE9 中自动降级
自定义的滚动条行为
2 VUE Router存在意义
2.1 传统页面跳转
在之前所有的页面都是由后端服务器进行页面跳转.所有的请求都会经过后端.导致后端服务器压力过大.
这种 用户只有通过后端服务器才能获取页面相关信息的方式 称之为 后端路由/服务器端路由.
弊端: 这种方式是一种集中式的管理. 性能瓶颈在服务器端.
2.2 解决策略
将所有的路由的配置生成JS,保存到浏览器中.当用户发起某个请求时,自己映射对应的请求页面信息(组件),之后直接访问静态资源.这样的方式速度更快。称之为: 前端路由/客户端路由
3 VUE Router入门案例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue路由嵌套</title>
</head>
<body>
<div id="app">
<!-- 2.定义路由链接 router-link 解析之后变为a标签 to 解析之后,变为href属性-->
<router-link to="/user">用户</router-link>
<router-link to="/dog">狗狗</router-link>
<!-- 3.定义路由填充位!该位置用来展现具体页面(组件) -->
<router-view></router-view>
</div>
<!-- 4.2 定义组件模版 -->
<template id="userTem">
<div>
<h1>我是组件的内容!!!</h1>
</div>
</template>
<template id="dogTem">
<div>
<h1>养个宠物狗</h1>
<!-- 定义子组件路由 -->
<router-link to="/dog/samo">萨摩耶</router-link>
<router-link to="/dog/hsq">哈士奇</router-link>
<!-- 定义子组件占位符 -->
<router-view></router-view>
</div>
</template>
<!-- 1.引入js函数类库 -->
<script src="../js/vue.js"></script>
<!-- 1.引入路由js 注意顺序不能颠倒 -->
<script src="../js/vue-router.js"></script>
<script>
// 4.定义组件
let user = {
//4.1定义页面
template : "#userTem"
}
let dog = {
template : "#dogTem"
}
let samo = {
template : `<h1>通体雪白的神兽</h1>`
}
let hsq = {
template : `<h1>拆家狂魔</h1>`
}
//5.创建路由对象,定义路由规则
let router = new VueRouter({
//定义路由规则
routes: [
/*
*利用redirect实现路由重定向
* 特点:1.重定向时URL中的请求地址发生变化
* 2.重定向时请求发送了多次,多次请求多次响应
* 3.重定向是服务器行为
* 4.重定向时不能传递参数
*/
{path: "/" , redirect: "/dog"},
{path: "/user" , component: user},
{path: "/dog", component: dog, children: [
{path: "/dog/samo", component: samo},
{path: "/dog/hsq", component: hsq}
]}
/* 该请求是根目录下的请求,所以组件的渲染也在跟组件
{path: "/dog/samo", component: samo},
{path: "/dog/hsq", component: hsq}*/
]
})
//6.将路由对象交给Vue对象管理
const vue = new Vue({
el: "#app",
//绑定路由
//router: router 名称一致时可以简化
router
})
</script>
</body>
</html>
十一、搭建前端框架
1 启动前端脚手架
1.1 启动命令
1.2 前端启动
1.3 前端环境准备
2 前端脚手架解构说明
2.1 关于.vue文件说明
之前编辑页面时采用.html文件进行操作, 但是在Vue脚手架项目 所有的页面都是.vue结尾.
.vue数据结构 分为三部分: 1.页面主体内容 template(html页面内容.) 2.JS操作部分. 3.页面样式的渲染.
2.2 脚手架文件结构
2.3 main.js说明
main.js 是控制整个脚手架的运行的初始的JS. 在其中一般设定公共的依赖信息(设定全局变量)
- 引入样式/JS/CSS
2.组件之间参数传递问题 父子组件通过属性prototype实现参数传递.
/* 导入axios包 */
import axios from 'axios'
/* 设定axios的请求根目录 */
axios.defaults.baseURL = 'http://localhost:8091/'
/* 向vue对象中添加全局对象 以后发送ajax请求使用$http对象 */
Vue.prototype.$http = axios
3.组件之间插件传递
import VueQuillEditor from 'vue-quill-editor'
/* 将富文本编辑器注册为全局可用的组件 */
Vue.use(VueQuillEditor)
4.实例化VUE对象 该对象指定渲染的页面,与页面中的区域.
new Vue({
//定义路由对象
router,
render: h => h(App)
}).$mount('#app')//绑定页面中的div元素
//上面两行代码类似于html代码中的 el: "#app"
2.4 App.vue 页面说明
说明: App.vue类似于index.html. 通过router-view 实现组件的动态的展现. 该路由占位符中显示的组件内容,通过路由进行控制.
<template>
<div id="app">
<!-- 添加路由占位符-->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "app"
}
</script>
<style>
</style>
2.5 脚手架中的路由
import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../components/Login.vue'
import FirstElementUi from '../components/FirstElementUi.vue'
import Home from '../components/Home.vue'
Vue.use(VueRouter)
const routes = [{
path: '/',
redirect: '/login'
},
{
path: '/login',
component: Login
},
{
path: '/elementui',
component: FirstElementUi
},
{
path: '/home',
component: Home
}
]
//定义路由对象
const router = new VueRouter({
routes
})
/*
* 设定路由导航守卫 相当于拦截器
* 参数说明: 1.to 要访问的路径 2.from从哪个路径来 3.next 请求放行
* 策略:1.用户访问/login 放行请求
* 2.如果用户没有访问登录页,则校验用户是否登录,校验token,有token应该放行,没有token应该跳转到登录页面
*/
router.beforeEach((to, from, next) => {
if(to.path === '/login') return next()
//用户访问网址不是/login 获取token
let token = window.sessionStorage.getItem("token")
//if(token != null && token.length>0) token有值
if(token) return next()
//如果程序执行到这一行,说明token没有数据,跳转到登录页面
next("/login")
})
//对外声明路由对象 子组件向父组件传递数据
export default router
2.6 脚手架加载流程图
3 前端JS分析
作用域插槽 一般用在循环遍历时,获取单行数据.
页面Ajax