vue常规篇
vue基本概念
- 单页面应用:在一个页面跳来跳去,不重新加载页面
- vue特点:渐进式、框架、双向数据绑定
- 双向数据绑定:视图改变、数据自动更新;数据更新、视图自动改变
- 渐进式:vue、vue-router路由、vuex axios
- 框架:自己写的代码被框架调用(库:自己调用库的代码)
- 声明式
vue核心实现方法
var obj={}
Object.defineProperty(obj,'name',{
value:'undefined',//包含这个属性的数据值。默认值为undefined
configurable:true,//表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,默认值为false
writable:true,//表示能否修改属性的值。默认值为false
enumerable:true,//表示能否通过for\in循环访问属性,默认值为false
set(val){
//只要外界给name赋值,就会触发该函数
//形参val就是外界赋予的值
},
get(){
return 123
}
})
vue大致框架
在一个html文件中,<html>和<script>都要用到vue专有的使用方式
<html>标签
- 在html文件中引入script的vue:
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
src = "https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"
或者
<!-- 生产环境版本,优化了尺寸和速度 -->
src="https://cdn.jsdelivr.net/npm/vue@2"
- vue后端获取放入js
原生js要后端获取到html(比如选择器),必须在<script>标签中写入:
let con = document.querySelector('选择器')
con.innerHTML = 'hello world'
这样写。开发效率慢,要直接操作dom,对浏览器来说开发效率慢;同时,性能会很差。
所以Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统:
<div id="app">{{message}}</div>
<script>标签:
var app = new Vue({
el: '#app',
// data不建议写成对象
data() {
return {
message: 'Hello Vue!'
}
}
})
其中data()为数据元
vue指令
v-if
用true和false来表示是否传递数据
html:
<div class="content" v-if="isShow">
{{message}}
</div>
script:
new Vue({
el: '#app',
data() {
return {
message: 'hello world',
isShow: false
}
}
})
v-show
和v-if差不多
如果需要非常频繁地切换,则使用 v-show 较好,如果在运行时条件很少改变,则使用 v-if 较好
若元素进入页面后,此元素只会显示或隐藏不会被再次改变显示状态,此时用 v-if 更加合适
反之使用v-show更好
v-else
v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。
v-if为true,v-else不出现;如果为false,则出现.
<h1 v-if='n===1'>hello</h1>
<h1 v-else-if="n===2">my</h1>
<h1 v-else>world</h1>
不用在new Vue中写
v-for
当需要遍历数组时使用
- html:
<li v-for="(item, index) in list" :key="index">
{{item}}
</li>`
- script:
new Vue({
el: '#app',
data() {
return {
message: 'hello world',
list: [2, 3, 7, 21, 65, 10]
}
}
})
其中item为数组中的每一项,index为下标
v-test
使用后不需要再挖坑{{}},直接用data里面的数据,即使文本有东西也优先用指令.同时,用标签仍会显示标签:
- html:
<div class="text" v-text="ohtml"></div>
- script:
new Vue({
el: '#app',
data() {
return {
message: 'hello world',
ohtml: '<h2>这是个富文本</h2>'
}
}
})
v-html
与v-text差不多,但标签会被编译
v-on
用于添加事件
当要设置一个点击按钮时,可以用button标签添加按钮
同时,用v-on的click触发点击事件,mouseover则鼠标划过就可以了
而后面的属性值为触发的方法methods
html:
<button v-on:click="add">add</button>
vue提供简便写法@代替v-on:
<button @click="add">add</button>
script:
new Vue({
el: '#app',
data() {
return {
count: 0
}
}
methods: {
add() {
this.count++
}
}
})
其中add函数中本来是this.data.count,vue简化了,可以直接写this.count
v-model
vue唯一实现了双向绑定的指令,放在input、textarea、select、option上
- v-model.trim去空格
- v-model.number输入的内容转换成数字
- v-model.change任何值发生变化都会被监听
- html:
<input type="text" v-model.number="inpVal">
- script:
new Vue({
el: '#app',
data() {
return {
inpVal: ''
}
}
methods: {
submit() {
this.inpVal = '双向绑定'
// console.log(this.inpVal);
}
}
})
代码中console.log(this.inpVal)把提交的值传递到methods中;methods则可以通过this.inpVal = '双向绑定' 传到data里,而框内也有值
v-bind
用来绑定属性
- css:
.title{
color: red;
}
.green{
color: green;
}
- html:
v-bind添加class,可以直接省略v-bind,简写成:
<div class="title" v-bind:class="active ? 'green' : ''" @click="addClass">
{{title}}
</div>
- script:
new Vue({
el: '#app',
data() {
return {
active: true
}
}
methods: {
addClass() {
this.active = !this.active
}
}
})
v-pre
不走vue语法直接走原生语法
<div class="pre" v-pre>{{preVal}}</div>
即使new Vue有数据,页面也直接显示{{preVal}}
v-cloak
css: 整个页面渲染完之后显示
[v-cloak] {
display: none;
}
script:
<div class="clock" v-cloak>{{message}}</div>
v-once
使用一次后之后数据会一直渲染在页面上,不需要再从数据元里取值
<div class="once" v-once>{{message}}</div>
vue 属性
- data(): 存数据,用return{}返回值,用{{}}来取值
- computed: 计算属性,动态的进行某些运算,属性名可以像data里的一样用{{}}来取得。只要依赖的数据源发生改变,就会重新执行。有缓存
- methods: 与之前一样
- watch: 监听器,当数据改变可以调用,并支持创建的对象可以获得新值老值。做不了缓存(面试官会问watch和computed的区别)。其中handler是固定写法。如下:
watch:{ handler(newVal, oldVal) { }, immediate:true } - mixins: 用于将外部的js代码混入生命周期内。用于生命周期内部代码过多时拿来减负。
vue data属性
vue对象
data中的属性最终都添加到了实例上 属性需要有get set,才能触发视图更新
let vm = new Vue({
el: '#app',
data: {
obj:{
a:123,//对于对象来说,新增一个属性不会触发视图更新,只有改变属性时才会触发视图更新
b:undefined,
}
}
}).$mount('#app')
//处理方式
//1.正常写全要用到的属性;先预留要用到的属性
//2.整个对象的重新赋值
//3.$set()方法
vm.$set(vm.obj,'c','456')
//4.增加一个无关变量t,每次修改完数据之后;重置t就可以了
vue数组
let vm = new Vue({
el: '#app',
data: {
ary: [1, 2, 3, 4]
}
})
vm.ary.length--;
//能改变原有数组,但不能触发视图更新,只有数组原型上的变异方法可以触发更新
//数组变异方法:pop shift unshift push reverse splice sort
vue method属性
vue事件
<body>
<div id="app">
{{ary}}
<button @click='fn'>按钮1</button>
<button @click='fn($event)'>按钮2</button>
<!-- $event是固定写法,代表传参事件对象 -->
</div>
</body>
</html>
<script src="./node/node_modules/vue/dist/vue.js"></script>
<script>
//事件绑定,用v-on:事件类型=‘函数’ 或者 @事件类型=‘函数’
//函数一般是在methods中定义的
//对应的函数一般不带小括号,默认传参事件对象e
//当我们需要传参时,需要加小括号,小括号里写需要传的参数;当只有小括号没有传参时,为undefined
//el data methods 都是VUE规定死的属性名
let vm = new Vue({
el: '#app',
data: {
ary: [1, 2, 3, 4]
},
methods: {
fn: function (e) {
console.log(e,this)
}
}
})
//@kryup.13='fn'在按下回车的时候才会触发该函数
</script>
vue filters属性
vue过滤器
全局用filter,实例局部使用filters 全局过滤器要放在需要使用的实例的前面
Vue.filter('qqq',function(val){
return val + 'hahaha'
})
let vm = new Vue({
el: '#app',
data: {
money:21546843
},
filters: {
//这里的函数中this是window不是实例
changeN(val, n=2) {
return (val/100).toFixed(n)
}
}
})
vue computed属性
- 于data同级别
- 语法同methods一样
- 计算属性的名字 不能跟 data 或 methods 中的名字重复
- 完全依赖于函数体中出现的属性名,只在最初加载时和其中属性名改变时运行,并不是像methods中的函数只要页面更新就运行一次
- 不能传参
- 异步的无法处理
- 为了提高性能而存在
vue计算
vue watch属性
- 当且仅当监听的属性(例如:name)发生变化时会执行函数
- 可以处理异步
- 下面这种写法不能监听引用数据类型的内部变化
vue监听
watch:{
name(newV,oldV){
clearTimeout(this.timer)
this.timer=setTimeout(() => {
if (newV.length > 5) {
this.msg2 = '名字太长'
}else{
this.msg2 = ''
}
}, 500)
}
}
深度监听:在有get和set属性时才会触发监听
watch:{
obj:{
handler(){
console.log(1111)
},
deep:true
}
}
生命周期篇
直接与数据元data()同级的
创建期间
-
beforeCreate:
Vue或者组件刚刚实例化,data、methods都还没有被创建
-
created
此时data和methods已经被创建,可以使用了。模板还没有被编译。
-
beforeMount
created的下一个阶段。此时模板已经被编译了,但是并没有被挂到网页上。
-
mouted
模板代码已经被加载到网页中了,此时创建的所有事件都已经准备好了,网页开始运行了。
运行期间
-
beforeUpdate
在网页运行期间, data中的数据可能会进行更新,在这个阶段,数据只是在data中更新了,但是并没有在模板中更新,因此网页中显示的还是之前的。
-
updated
数据在 data中更新了,也在网页中更新了。
销毁期间
-
beforeDestroy
Vue实例或者是组件在被销毁之前执行的函数,在这一个函数中 Vue或者组件中所有的属性都是可以使用的。
-
destroyed
Vue 实例或者是组件在被销毁后执行的。此时Vue实例上所有的东西都会解绑,所有事件都会被一处,所有的子元素都会被销毁。
调用时间总结
Vue Cli篇
基于Vue.js进行快速开发的系统
安装与创建vue文件夹
指令:npm i @vue/cli -g
查看版本:vue -V
创建文件夹:vue create (文件名)
如果装东西慢可能是网络问题,可以选择换npm为淘宝源
运行vue cli文件: npm run serve
指明安装版本:npm i vue-router@3.2.0
vue cli的组成
如图:
下载的文件中,包括:
- node_modules(脚手架): 包含vue源码以及所需依赖
- public:
- favicon.ico: 页面标题的图形
- index.html: 单页运用,最主要的页面,其他页面用js拼接到这里,再通过其他手段只显示一个页面实现页面切换
- src:主要开发的平台
- asset: 存储静态资源,如图片
- components: 所有组件都放这里如创建helloworld.vue则在App.vue可以调用
<helloworld>- App.vue: 最根本的vue文件
- template标签:vue独有,可以装html5代码
- script标签:用于写js代码
- style标签:用于写css代码
- main.js: 最根本的js文件
- App.vue: 最根本的vue文件
- gitignore: 检查那些代码没提交时,过滤掉写在里面。其中node_modules默认不提交到项目。
- package.json: 所要装的依赖的说明书(加dev开发环境不加生产环境)
- "devDependencies"根据这里装所需的依赖
- "dependencies"必装的环境
- "script"执行npm run (文件名)用于跑项目
- babel.config.js: 把es6转换成es5
- jsconfig.json:
- "target"es转换成指定版本
- package-lock.json: 记录依赖从哪里装的
- package.json: 记录装了什么依赖
- vue.config.js: vue官方配置文件
vue引入的组件的三步
- 在script中引入 import (组件名) from '(文件夹)'
- 在export default(相当于new Vue)中的components中声明(组件名)
- 在template中使用
父组件向子组件传值:用一个定义的属性来传值。 属性则是在子组件的export default中定义对象来实现
结构与App.vue差不多,放在components文件夹里
vue router(路由)篇
配置vue router
创建vue cli,选第三个
之后能查看到。。。
其中包含以下内容:
- progressive:插件
- router:路由
- vuex:一个仓库
- css pre-processors:预处理器
- linter/formatter:eslint 下面的是两个测试功能
按上图配置,然后会显示你要安装的eslint版本,选第一个报错最少的:
然后选择保存后校验:
选择一个格外的配置文件,尽量不放在package中:
vue router相比vue cil的文件改动
- eslintrc: 包含使用的校验规则rules(里面的process代表node)
- src
- router 路由都在这配
- views 视图,把页面都放在此处
- components 组件全放在这
内部代码模板
main.js
- main.js将App.vue引入进来
- render:
h=>h(App)把App.vue里面的代码,拿到render生命周期函数编译 .$mount('#app')指挂载到#app这个容器中去,#app在index.html中
App.vue
<template><nav>标签,为html5本来就有的<router-link>标签,vue专有,表示路由导航- to属性:调到指定模拟页面
- 可以用:
to="{name: '名字', params:{user:'自定义'}}"和to="{path: '路径'}"来进行跳转,params为携带的参数(只有name能携带)
<router-view>让<router-link>指定的页面搬到这里来展示- 不加name ,默认为首页vue的代码
- 加name,可以匹配多个js页面
index.js
- 引用Vue、VueRouter和要调用的页面
- Vue.use(VueRouter)让VueRouter在Vue里面生效
- use将Vue的代码和()里面的代码合并
- routes
- path 地址
- name 没有什么实质性的作用,传参有用
- component 组件,有两种调用方法:
- 直接通过import form引用
- 按需加载路由页面 (推荐): component: () => import('地址')
- components 组件
- 可以放default left right
- children 用于接收子路由
- 二级路由的path除了首页不用加'/',坑
- router
- mode 两种模式-history\哈希模式
- base 保证了路径只需写后半段,基础的已经写好
跳转页面
- 通过name跳转页面
- 也可以用path跳转页面
vue路由传参的四种方式
- 直接通过name传参 //路由配置
{
path:'/',
name:'home',
component:Home
}
//组件获取
{{$route.name}}
- 通过router-link :to的name属性来传
<router-link :to="{path:'/'}">
携带参数只能用name
<router-link :to="{name:'home', params:{user:'蜗牛'}">首页<router-link>
路由配置
{
path:'/',
name:'home',
component:Home
}
组件获取
{{$route.params.user}}
- 一个页面有多个应用区域
创建left、right组件
<router-view></router-view>
<router-view name="left"></router-view>
<router-view name="right"></router-view>
路由配置
{
path:'/',
name:'home',
components:{
default:Home,
left:Left,
right:right
}
}
- 通过path路径
<router-link to="/hot/123">
路由配置
{
path:'/hot/:id',
name:'hot',
components:Hot
}
组件获取
{{$route.params.id}}
- 用例如click事件来获取,编程式导航
<span @click="goLive">活动<span>
- 如果用
params进行传参,一定要用name属性来对应跳转路径 - 如果用
query进行传参,一定要用path属性来对应跳转路径
export default {
methods: {
goLive() {
//router不是route 是new Vue实例对象
this.$router.push({path:'/live', query: {name:蜗牛}})
this.$router.push({name:'live', params: {name:蜗牛}})
}
}
}
路由配置
{
path:'/live',
name:'live',
components: () => import('../views/Live.vue')
}
组件获取
query隐私不安全,能用就用 params隐私但只能一次
{{$route.query.name}}
{{$route.params.name}}
组件通信篇
父组件传参
- 环境
父子组件文件位置
- 父组件
<childVue :count="count"></chlidVue>,将count值传给子组件<button @click="() => {} >传给子组件。其中,{}里面引用的数据不用this.count。等同于在export default里的methods
- 子组件
props为简写,接收父组件传过来的值
- 结果
父子组件同时加
子组件传参
- 子组件
往外传给父组件
- 父组件
script代码:
兄弟组件
- 方法一:兄组件传父组件再传弟组件
- 父组件
- 兄组件
- 兄组件往外传
- 在父组件中接收
- 父组件使用方法
- 父组件传给弟组件
- 弟组件接收
缺点:由于只能兄传父传弟,如果兄有儿子那么只能从下往上再从上往下,不方便
- 方法二:兄组件传给中间组件再传给弟组件
使用.$on让弟直接接收.$emit传来的值,.$on里面第二项的回调函数,但传递需要一个渠道所以在src中设置一个bus.js(@/为src)
- 兄组件引入bus.js,不再用this,改用bus
- 弟组件引入bus.js,不再用this,改用bus
- bus.js 设置:原理就是实例化了一个vue,实例化的对象给到了兄弟 而this指向的是自己的default对象,所以用同一个实例对象bus.js(又名eventBus)
vuex篇
概念
vuex,是一个能方便vue实例及其组件传输数据的插件,方便传输数据,作为公共存储数据的一个库
内部代码模板
- main.js
官方开发的东西都放这
- index.js
里面的对象都是内定好的
方法汇总
state
存值方法,类似vue实例中的data,存储数据。在vue实例中用this.$store.state调用state里的数据使用...Vuex.mapStore(['count'])将其数据放入computed中
- mapState可用来传递state的数据
- 可以简写
- 也可以传多个值
mutations
mutations 修改仓库数据元的方法(可以异步但建议不用异步),执行是同步先执行异步挂起,通过commit来调用mutations中的函数,其中函数最少有一个参数state,最多两个参数另加val(调用时的传参) 使用...Vuex.mapMutations(['mu_add'])将其函数放入methods中
- mutations可以直接调用state里的值
- vue文件中,mutations里的方法用
$store.commit提交,方法在仓库操作state的值,再用后面传该方法需要的其他值 - mapMutations用来取仓库的方法
...: 把mapMutations解构出来
action
actions与mutations差不多,但主要放异步(宏任务微任务),一般多用于触发ajax请求,不能直接用于修改state中的数据,需要通过其中函数默认的第一个实参obj,用obj.commit('mu_')来调用mutations中的函数来修改数据 使用...Vuex.mapActions(['ac_add'])将其函数放入methods中
- mapAction用来取仓库的方法
...: 把mapMutations解构出来
2. 也可以用dispatch分发action
getters
计算属性,存储数据,使用...Vuex.mapGetters(['remove'])将其函数放入computed中
- getters导致state的数据改变
...mapGetters将解构出来
只能解构到computed不能直接放在data中
module
存放额外的数据元
-
modules的调用extre,extre的值以extre的对象存入state 、mutations、actions之中
-
vue文件中调用mouble里的extre
-
可以往仓库里塞值,但尽量别这么干,页面过多难被人看到
context调用方法
context可以直接调用其他4个对象。
context存在context.commit()方法,而{commit}为对象的解构相当于context.commit(),建议使用
vue移动端兼容解决方案--rem.js
rem.js用来设置移动端页面的兼容性 整体为一个自执行函数 window的意思为“窗口”,是一个内置的宿主对象,表示浏览器窗口,所有浏览器都支持该对象。所有JavaScript全局对象、函数以及变量均会自动成为window对象的成员.
- document:、:是文档对象的意思,代表浏览器窗口的文档
- docEl:如图
- resizieEvt:可以触发后面的事件没有触发第二个用于改变页面在移动端浏览器的大小
- recalc:拿到页面宽度计算根子体大小
- win:手动缩放时确定根子体的改变
- doc:触发DOM事件确定根子体的改变
发接口请求获取数据-axios
- 安装
- 引入
- 使用
vue-router导航守卫篇
主要用来通过跳转或取消的方式守卫导航
.$route和.$router
.$route与更换浏览器路径相关,vue用来封装当前路径,用于在url页面取东西.$router与跳转页面相关,代表路由实例
存储登录页面的信息
local 永久存储
session 只存储当前窗口
路由守卫
全局路由守卫
是指路由实例上直接操作的钩子函数,触发路由就会触发这些钩子函数。
- 全局前置守卫
beforeEach
在路由跳转前触发,一般被用于登录验证
- to:目标路由对象
- from:即将要离开的路由对象
- next:三个参数中最重要的参数
- 必须调用
next(),才能继续往下执行一个钩子,否则路由跳转会停止 - 若要中断当前的导航,可以调用
next(false)。 - 可以使用next跳转到一个不同的地址。终端当前导航,进入一个新的导航。next参数值和
$routet.push一致。 - next(error),如果传入的参数是一个Error实例,则导航会被终止,且该错误会被传递给
router.onError()注册过的回调。
- 必须调用
- 全局解析守卫
beforeResolve
和boforeEach类似,路由跳转前触发。
和beforeEach的区别:在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
3. 全局后置钩子afterEach
和beforeEach相反,路由跳转完成后触发。
路由独享守卫
是指在单个路由配置的时候也可以设置的钩子函数。
- beforeEnter
和beforeEach完全相同,如果都设置则在beforeEach之后紧随执行
路由组件内的守卫
不光可以在路由跳转前后,设置守卫,也是可以在路由组件内定义路由的导航守卫。
beforeRouteEnter
在渲染该组件的对应路由被confirm前调用.不能获取组件实例 this 因为当守卫执行前,组件实例还没被创建。
2. beforeRouteUpdate
在当前路由改变,但是该组件被复用时调用,举例来说,对于一个带有动态参数的路径/foo/:id,在/foo/1和/foo/2之间跳转的时候,由于会渲染同样的Foo组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
完整流程:
- 导航被触发。
- 在失活的组件里调用
beforeRouteLeave守卫。 - 调用全局的
beforeEach守卫。 - 在重用的组件里调用
beforeRouteUpdate守卫。 - 在路由配置里调用
beforeEnter。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter。 - 调用全局的
beforeResolve守卫。 - 导航被确认。
- 调用全局的
afterEach钩子。 - 触发 DOM 更新。
- 调用
beforeRouteEnter守卫中传给next的回调函数,创建好的组件实例会作为回调函数的参数传入。
后记
希望能对你的学习有帮助,文章可能存在一些问题,会进行后继修改!