①Vue是一套构建用户界面的渐进式框架;
与其他重量级框架不同的是,Vue 采用**自底向上增量开发**的设计。
Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。
② 核心理念:组件化开发、数据驱动视图 ( 双向数据绑定 )
MVC是前后端未分离时的分层开发概念,MVVM是前后端分离后的前端开发的概念;
细说就是( 以下为个人理解,或有谬误,欢迎指正 ):
MVC和MVVM中的Model层都用于数据操作,但是二者有本质区别,MVC中的Model是真正的服务端数据库,
MVVM中的Model本身的数据量很小,大部分所需数据都是从服务端请求回来的;
MVVM中的View视图层,是用户能够看到并进行交互的客户端界面;
整个MVVM都属于MVC中的View视图层。
MVC中的 Controller 业务逻辑层负责收集用户输入的数据,向相关Model请求数据并返回相应的视图来完成交互请求
MVVM中的ViewModel层也是业务逻辑层,或者说调度层,是MVVM中的核心概念,它实现了双向数据绑定:
可以把Model层的数据渲染到View视图层,同时View视图层的数据发生改变也可以自动同步到Model层中;
VM解放了前端程序员的双手,前端程序员不用再进行不必要的DOM操作了,只需关心前端的业务逻辑即可
框架是一套完整的解决方案;对项目的侵入性较大,项目如果需要更换框架,则需要重新架构整个项目。
例如:node中的express
库(插件):提供某一个小功能,对项目的侵入性较小,如果某个库无法完成某些需求,可以很容易切换到其它库实现需求。
例如:从Jquery 切换到 Zepto
插值表达式: {{}} , 使用v-once指令可以执行一次性的插值,当数据改变时,插值处的内容不会更新
v-cloak
<style>
[v-cloak] {
display: none;
}
style>
<div v-cloak>{{msg}}div>
原理:数据没加载好之前隐藏显示,加载好之后再显示
①相同之处:v-html 和 v-text 都会覆盖元素原来的内容
②不同之处:v-html 可以解析富文本,但 v-text 不行
指令: v-bind:
简写为冒号:
指令:v-on:
简写为艾特符号@
.self
、 .once
、 .stop
、 .prevent
、 .capture
事件修饰符可以连用,即链式书写,但.once和.prevent连用会引发一个问题
(例如在表单提交按钮下使用,第一次提交失效后,再按就会刷新页面,然后又可以继续提交并刷新页面)
一般只在 input 标签中使用,指令:v-model:value=“”,简写:v-model=“”
a)遍历数组:(item,index) in list :key="index"
b)遍历对象:(value,key,index) in obj :key="value.id"
c)遍历数字:num in 1234 :key="num"
v-if 是删除和添加dom元素,v-show 是设置元素的display属性来完成显示与隐藏效果
:class="'normal'"
:class="{'big':true}"
对象的键是样式的名字,值是Boolean类型:class="[csgo,styleArr]"
:class="[csgo,{ bigFontSize : flag }]"
:class="flag ? csgo : styleArr"
直接在:style=""里写样式对象,记得加单引号
:style="{'font-size':'30px'}"
在data里定义样式对象然后直接引用
<p :style="innerStyle">data里定义一个对象,对象里直接设置样式p>
innerStyle: {
color: 'red',
fontSize: "25px"
}
:style = "[innerStyle, innerStyle2, innerStyle3]"
<p :style="setStyle()"> csgo p>
setStyle() {
return { color: "green", fontSize: "25px" }
}
全局:
Vue.filter("过滤器名称",function(data,format){
return ......
})
局部:
filters:{
过滤器名称:function(data,format){
return ......
}
}
过滤器可以用在两个地方:插值表达式和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。
插值表达式:{{ message | filterA | filterB }}
v-bind表达式:
Vue.config.keyCodes = {
v: 86,
f1: 112,
// camelCase 驼峰命名法不可用
// mediaPlayPause: 179,
// 取而代之的是 kebab-case 我称之为横杠连接法,且用双引号括起来
"media-play-pause": 179,
up: [38, 87]
}
或单个按键:Vue.config.keyCodes.j = 74
全局定义:
<script>
Vue.directive('focus', {
// 只调用一次,指令第一次绑定到元素时调用。
//在这里可以进行一次性的初始化设置。
bind(el, bingding) {
el.style.color = "red"
},
// DOM元素渲染完毕后执行
inserted(el) {
el.focus()
},
// 元素有更新时执行
update(el) {
el.style.fontSize = '18px'
}
})
script>
局部定义:
let vm = new Vue({
el: "#box",
data: {
color: "hotpink"
},
methods: {
},
directives: {
big: {
bind(el, binding) {
el.style.fontSize = binding.value
}
},
color: {
bind(el, binding) {
el.style.color = binding.value
}
},
'focus-auto': {
// 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
bind(el, binding) {
el.style.color = "red"
},
// 元素渲染完毕后执行
inserted(el) {
el.focus()
},
// 元素有更新时执行
update(el) {
el.style.fontSize = '18px'
}
}
}
})
el:指令所绑定的元素,可以用来直接操作 DOM;
binding是一个对象,里面有n多属性,value是其中的一个
使用: DOM元素里添加 v-自定义指令名称=“binding.Value”
<input v-focus-auto="" type="text">
1. beforeCreate()
2. created()
3. beforeMount()
4. mounted()
5. beforeUpdate()
6. updated()
7. beforeDestroy()
8. destroyed()
beforeCreate生命周期钩子函数:
初始化尚未完成,data数据,methods方法都未挂在在vue实例上
一般用于页面重定向
created生命周期钩子函数:
初始化已经完成,data数据,methods方法都可以被调用了
是第一个能操作data中数据对象和调用methods方法的生命周期,
一般用于接口请求+数据初始化
beforeMount生命周期钩子函数:
进入运行阶段前;此时虚拟dom尚未挂载,页面元素尚未更新
mounted生命周期钩子函数:
dom元素挂载后,如果需要操作dom,可以在此mounted周期执行
beforeUpdate生命周期钩子函数:
元素发生更新时,元素更新前的阶段;可以执行0次到多次;
updated生命周期钩子函数:
元素发生更新时,元素更新完成的阶段;同样可以执行0次到多次;
beforeDestroy生命周期钩子函数:
vue销毁前的阶段,一般用来清除定时器等操作。
destroyed生命周期钩子函数:
vue销毁后的阶段,好像没什么用。
GET请求:this.$http.get(URL)
POST请求:this.$http.post(URL, {参数} , {emulateJSON})
{ emulateJSON } 默认为false
第三个参数是: {emulateJSON}
用来设置POST请求提交的参数编码类型是否为 application/x-www-form-urlencoded;
值为 false 时参数类型默认为application/json
,默认编码格式为charset=UTF-8 。
发送GET请求:axios.get(URL)
发送POST请求:axios.post(URL,{JSON参数})
如果参数类型不是application/json
则需要使用内置参数对象
let formData = new FormData();
let params = new URLSearchParams();
v-enter(vue3中为v-enter-from)、v-enter-to、v-enter-active
v-leave(vue3中为v-leave-from)、v-leave-to、v-leave-active
引入animate.css,直接使用它的类名:
enter-active-class = "animated slideInRight"
leave-active-class = "animated bounceOutRight"
@before-enter @enter @after-enter
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter">
<div v-if="isshow" class="show">OKdiv>
transition>
定义三个 methods 钩子方法:
methods: {
beforeEnter(el) { // 动画进入之前的回调
el.style.transform = 'translateX(500px)';
},
enter(el, done) { // 动画进入完成时候的回调
el.offsetWidth;
el.style.transform = 'translateX(0px)';
done();
},
afterEnter(el) { // 动画进入完成之后的回调
this.isshow = !this.isshow;
}
}
需要使用
组件把v-for循环的列表包裹起来
<transition-group tag="ul">
<li v-for="(item, i) in list" :key="i">{{item}}li>
transition-group>
先写一个组件标签:
<template id="tmpl">
<div><a href="#">登录a> | <a href="#">注册a>div>
template>
全局声明方式:
Vue.component("组件名",{
template:"#组件id"
})
私有声明方式:
const vm = new Vue({
el: '#app',
data: {
flag: true
},
methods: {},
components: {
"register": {
template: "#register"
},
"test": {
template: "#login"
},
// 必须写ID,不可以写类名
// "lll": {
// template: ".lllllll"
// }
}
})
props属性
配置项(和data同级),在props属性中设置接收数据的名称与类型,可以使用数组设置多个接收类型,也可以使用 default函数 设置默认值; <course :type="theFree">course>
<script>
Vue.component("course", {
template: "#course",
props: {
type: String,
'page-num': [Number, String],
'page-size': [Number, String],
test: {
type: String,
default: function () {
return '这是一个默认的名字'
}
},
},
data() {
return {
courseList: [],
}
},
})
script>
子组件标签中绑定自定义事件,在子组件的methods里声明自定义事件,书写方法体, 调用this.$emit('自定义事件名称',传递数据)
方法
父组件的methods里声明自定义事件的接收方法(@xxxx=“xx” 后面的xx)
触发自定义事件,子组件传值,父组件接收(接受方法中的第一个参数data就是传来的数据,也可以第一个参数传 $event,第二个参数接收数据)
使用: 在组件中声明
标签,填充插槽时直接在组件标签里写填充内容
区别: 默认插槽声明时直接写
,使用时可以直接在组件标签里写填充内容;
具名插槽在声明时要加一个name属性,
填充时要写template标签:填充内容
后端路由:
所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源,切换页面时每次都向后台服务器发出请求,服务器响应请求,会打开新页面或者刷新页面
前端路由:
对于单页面应用程序来说,主要通过URL中的 hash(#号) 来实现不同页面之间的切换,每次跳转到不同的URL都是使用前端的锚点路由,不会重新请求和刷新页面。
同时,hash有一个特点:HTTP请求中不会包含hash相关的内容;
这种通过hash改变来切换页面的方式,称作前端路由(其中的一种,还有一种history模式,不带#号)
引入js文件,这个js需要放在vue.js后,自动安装(提供了一个VueRouter的构造方法)
使用 new VueRouter() 构造方法创建路由实例,构造方法可以接收一个参数,参数类型为对象类型
在参数对象中配置属性 routes:[]
,这个数组中的元素是路由对象,路由对象里包含path属性和component属性
path属性是 路由的路径,即在哪个路径下显示哪个组件 ,component属性就是这个路径下要显示的组件(直接传组件对象,不加引号)
创建的router需要和vue实例关联一下,将路由实例挂载在vue实例上
在可操作区域中预留路由的显示位置,即指定在特定路径时,路由中的组件显示在哪个位置,需要使用标签:
路由的声明式跳转需要使用:router-link 标签,标签中有一个 to 属性,它的属性值是路由的路径;
函数式跳转:this.$router.push({ path: '/index' })
<button @click="toIndex">回到主页按钮button>
<script>
toIndex() {
this.$router.push({ path: '/index' })
}
script>
问号拼接后参数<-->
<router-link to="/index/login/personal?id=1&name=张三" tag="button">去个人中心页router-link>
模板字符串<-->
去个人中心页router-link>
对象形式<-->
<router-link :to="{path:'/index',query:{id,name}}" tag="button">去个人中心页router-link>
params传参:
需要先在路由对象的path属性中声明参数占位符:
path: "personal/:id/:name"
直接传参<-->
<router-link to="/personal/666/张三" tag="button">去个人中心页router-link>
模板字符串的形式<-->
<router-link :to=`/index/login/personal/${id}/${name}` tag="button">去个人中心页router-link>
对象的形式<-->
<router-link :to="{name:'personal',params:{id:'666',name:'张三'}}">去个人中心页router-link>
this.$router.push({ name:'index', query:{id:666,name:"张三"} })
this.$router.push({ name:"personal", params:{id:666,name:"张三"} })
中。const router = new VueRouter({
routes: [
{
// 初始页面路径重定向
path: '/',
redirect: '/index'
},
{
path: '/index',
component: index,
children: [
{
// 不加/使用的是相对路径,后面也可以直接跟参数什么的
path: 'login',
component: login,
children: [
{
path: "personal",
component: personal
}
]
}
]
},
]
})
Vue-router 提供了一个现成的类名 .router-link-active 来设置选中路由的样式,
我们只需要在 CSS 中自定义自己喜欢的样式即可,比如选中后变红,字体变大
自定义选中路由高亮类名只需配置这个配置项:linkActiveClass: “iChooseYou”
<p ref="test">我是p标签,我打了个ref标识p>
<course ref="test2">我是自定义组件,我打了个ref标识course>
获取元素:this.$refs.xxx
例如 :在可操作区域内,this.$refs.test 就能拿到这个DOM元素
computed:{
属性名:{
get(){
return ...
},
set(newValue){
...
}
}
}
需要双向绑定:
当你确定了属性只会被读取而不会被改变时可以采用简写的方式:
属性名(){return ...}
watch:{
需要监视的属性名:{
//初始化时让handler调用一下
immediate:true,
handler(newValue,oldValue){
//handler在监视的属性的属性值发生变化时调用
......
}
}
}
如果你确定不需要用到 immediate 和深度监视 deep,那么就可以使用简写,
用到其中的任何一个都不能使用简写:
需要监视的属性名(newValue,oldValue){......}
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。
它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
①当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏
②vuex解决了多组件之间状态共享的问题,不用再把数据互相传来传去了。
官方单向数据流示意:
状态:驱动应用的 数据源;
视图:以声明方式将 状态映射 到视图;
操作:响应在视图上的用户输入导致的状态变化。
Vuex有五大核心概念(模块),即:
关于它们的具体作用及如何使用可移步至:Vue基础 -Vuex
由于Vuex的数据是存储在内存中的,相当于memory cache,当页面刷新的时候内存被清空重载新内容,原来的数据就丢了。
为了解决这个我们可以借助浏览器的本地存储来解决,即:
根据需求自行选择即可,一般使用sessionStorage,因为localStorage太持久了。
或者,还有一种特殊情况,比如验证用户是否已经是登录状态,如果登录状态存储在Store中,每次刷新页面这个登录状态数据就没了。
此时也可以在后台专门设置一个接口来返回用户登录状态,每次刷新页面都重新请求这个接口也可以达成目的。(只是一种方法,不是最优解)
路由守卫是路由在跳转前、后过程中的一些钩子函数,这些函数可以让你操作一些其他的事,在后台管理中设置权限时经常看到,在实现路由跳转前校验是否有权限,有权限就可以通过,反之就会被执行其他操作,如返回首页。
路由守卫的参数:
to:目标路由对象
from:即将要离开的路由对象
next():放行(可选参数)
路由守卫分为:全局守卫,组件内的守卫,路由独享守卫
const router = createRouter({ ... })
router.beforeEach((to, from) => {
// ...
// 返回 false 以取消导航
return false
})
const UserDetails = {
template: `...`,
beforeRouteEnter(to, from) {
// 在渲染该组件的对应路由被验证前调用
// 不能获取组件实例 `this` !
// 因为当守卫执行时,组件实例还没被创建!
},
beforeRouteUpdate(to, from) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1` 和 `/users/2` 之间跳转的时候,
// 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`
},
beforeRouteLeave(to, from) {
// 在导航离开渲染该组件的对应路由时调用
// 与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`
},
}
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: (to, from) => {
// reject the navigation
return false
},
},
]
更多详情请移步至此博主:元元元缘 或 官方文档