1、MVC、MVP与MVVM模式
MVC是应⽤最⼴泛的软件架构之⼀,⼀般MVC分为:
Model( 模型 )、Controller( 控制器 )、View( 视图 )。
这主要是基于分层的⽬的,让彼此的职责分开。View ⼀般通过 Controller 来和 Model 进⾏联系。Controller是 Model 和 View 的协调者,View和Model不直接联系,基本联系都是单向的。
1、View 传送指令到 Controller
2、Controller 完成业务逻辑后,要求 Model 改变状态
3、Model 将新的数据发送到 View,⽤户得到反馈
MVP 模式将 Controller 改名为 Presenter,同时改变了通信⽅向。
1、各部分之间的通信,都是双向的。
2、View 与 Model 不发⽣联系,都通过 Presenter 传递。
3、View ⾮常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,⽽ Presenter⾮常厚,所有逻辑都部署在那⾥。
MVVM
MVVM 是把 MVC 的 Controller 和 MVP 的 Presenter 改成了 ViewModel。View 的变化会⾃动更新到 ViewModel,ViewModel 的变化也会⾃动同步到 View上显示。这种⾃动同步是因为 ViewModel 中的属性实现了 Observer,当属性变更时都能触发对应的操作。
2、单文件组件的创建:template
<template>
<div class="hello">
<h1>第一个单文件组件</h1>
<p>我的名字叫:{{myname}}</p>
</div>
</template>
<script>
// 单文件组件的使命是被别人引入来使用
// 传统方式是使用module.exports来暴露成员
// 建议的方式是使用export default,这是用来暴露默认成员。因为一个vue文件只描述一个组件,所以这个组件就可以当成默认需要返回的对象
// export default所返回的对象就是当前vue文件所描述的组件对象,这个组件对象是包含着完整的结构功能和样式
// 我们所返回的对象本质是是编译完成之后的组件对象,里面当然包含着结构功能和样式
export default {
data(){
return {
myname:'小明同学'
}
}
}
</script>
<style lang='less' scoped>
// lang:可以指定样式的类型,如指定预处理器less
// scoped:定义当前样式是组件作用域样式:只有在当前组件中可以使用
h1{
color:red;
}
</style>
3、插值表达式、v-text 、v-html、v-bind、v-for、v-model、v-on、v-show 、v-if
插值表达式 <p>{{msg}}</p>
v-text
1.v-text中可以写和插值一样的表达式
2.V-text会将标签之间的内容完全替换,而插值可以根据需要部分替换
<p v-text="msg">不要干掉我</p>
v-html
1.它可以解析html结构
2.它会完全的覆盖标签之间的原始的内容
<p v-html='msg'>aa</p>
v-bind
链接: <a v-bind:href="'/del?id='+id">删除</a>
样式:<p v-bind:style='"font-size:"+fontsize'>我有自己的字体大小</p>
类:<p :class="{red:isred}">我是红色吗?</p>
v-for
1.循环数组
<标签 v-for='(value,index) in arr' :key='index'></标签>
2.循环对象
<标签 v-for='(value,key,index) in obj' :key='key'></标签>
:key属性具有唯一性,不能重复,它能够唯一标识数组的每一项
将来数据中的某一项的值发生了改变,则v-for只会更新当前项对应的这个dom元素的值,而不是更新整个数据,从而提高效率
v-model
实现双向绑定的
1.修改数据,页面内容动态变化
2.修改页面内容,数据也有相应的动态变化
用户名: <input type="text" v-model="username"> <br>
密码:<input type="password" v-model="password"> <br>
export default {
data () {
return {
msg:'hello',
username:'',
password:''
}
}
v-on
作用就是用来对元素进行事件绑定的
<标签 v-on:事件类型='事件处理函数'></标签>
<标签 v-on:事件类型='事件处理函数(参数)'></标签>
简写语法 :<标签 @事件类型=‘事件处理函数’>
v-show和v-if
都能实现元素是否显示在页面中
<标签 v-show='bool值'>
<标签 v-if='bool值'>
如果bool值为True,则显示,否则看不到
v-show:是通过为元素设置display:none的样式来实现元素的显示和隐藏的,如果是隐藏则添加这个样式,否则不添加这个样式
v-if:是通过元素的创建和销毁来实现元素是否可见,如果为true,则创建这个元素,否则不创建。
v-if分支结构v-else-if
其他指令
v-pre:原样输出,不解析当前的指令
v-once:只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能
v-cloak:这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如 [v-cloak] { display: none }
一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕
4、ref和$refs
类似dom的元素选择方式:document.querySelector(‘input’)
// 为元素设置ref属性
编号:<input type="text" v-model="newbrand.id" ref="bid"/>
// 在mounted钩子函数中通过this.$refs获取元素,并设置聚焦
mounted () {
console.log(this)
// 获取元素,设置聚焦
this.$refs.bid.focus()
}
5、局部指令
创建
export default {
directives: {
// 指令名称:{配置定义}
myfocus: {
// 当被绑定的元素插入到 DOM 中时…当指令添加到元素,正准备进行解析渲染时
// 参数:
// 1.el:当前使用这个指令的元素
inserted (el) {
console.log(el)
el.focus()
}
},
// 设置颜色
setcolor: {
inserted (el, binding) {
console.log(binding)
el.style.color = binding.value || '#000'
}
}
}
}
使用
<input type="text" v-model="newbrand.bname" ref='bname' v-myfocus/>
6、全局指令
在utils创建mydirectives.js文件
export const myFocus = {
inserted (el) {
console.log('这是全局指令的功劳')
el.focus()
}
}
export const setcolor = {
inserted (el, binding) {
el.style.color = binding.value
}
}
使用
import { myfocus, setcolor } from '../utils/mydirectives.js'
export default {
// 注册指令
directives: {
myfocus: myfocus,
setcolor
}
}
<input type="text" v-model="newbrand.bname" ref='bname' v-myfocus/>
7、过滤器
局部
export default {
// 添加过滤器
filters: {
dateFormat: (data, spe) => {
var year = data.getFullYear()
var month = data.getMonth() + 1
var day = data.getDate()
return year + spe + month + spe + day
}
}
}
使用
<td>{{value.btime | dateFormat('/')}}</td>
全局
在utils创建myfilters.js文件
export const dateformat = (data, spe) => {
spe = spe || '/'
var year = data.getFullYear()
var month = data.getMonth() + 1
var day = data.getDate()
return year + spe + month + spe + day
}
使用
import { dateformat } from '../utils/myfilters.js'
export default {
// 注册过滤器
filters: {
dateformat
}
}
<td>{{value.btime | dateformat}}</td>
8、计算属性
它能监听当前的指定的依赖项的变化,从而进行相应的处理,并返回处理的结果。但是计算属性无法响应异步操作中依赖项的数据变化
// 添加计算属性
computed: {
formatString () {
return this.msg.substring(0, 1).toUpperCase() + this.msg.substring(1).toLowerCase()
}
}
调用
<h1>{{formatString}}</h1>
9、监听器
1.侦听器的函数名称必须和你想侦听的属性名称完全一致
2.侦听器不能手动的调用,它是自动触发的
3.侦听器中一般不会返回值
4.它能响应异步操作中的数据变化
export default {
data () {
return {
msg: 'hello',
myname: 'jack'
}
},
watch: {
// 你想侦听哪个属性,就必须以这个属性做为侦听器的名称
// newv:新的值, oldv:旧的值
msg (newv, oldv) {
console.log(newv, oldv)
}
}
}
深度监听
- 第一种方式
users: {
// 添加handler方法,这个函数可以侦听指定对象的属性值的变化
// 修改这个对象的任何一个属性都会触发
handler () {
console.log('aa')
},
// 设置当前侦听为深度侦听
deep: true
}
- 第二种方式
// 侦听指定的属性值的变化
'users.username' (n, o) {
console.log(n, o)
}
10、axios
get方式的无参请求
// 获取所有分类数据
getCateList () {
axios.get('http://127.0.0.1:4444/getCateList')
.then((res) => {
console.log(res)
})
.catch((err) => {
console.log(err)
})
get的带参请求
axios.get(’/路由?参数名称=参数值&参数名称=参数值’)
- 方式一
// 根据id获取文章详情数据
getPostById () {
axios.get('http://127.0.0.1:4444/getPostById?id=5')
.then((res) => {
console.log(res)
})
.catch((err) => {
console.log(err)
})
}
- 方式二
axios.get('http://127.0.0.1:4444/getPostById', {
params: {
id: 10
}
})
.then((res) => {
console.log(res)
})
.catch((err) => {
console.log(err)
})
post请求
语法:
axios.post('路由',{数据对象})
.then(请求成功之后的回调函数)
.catch(请求失败之后的回调函数)
export default {
data () {
return {
cate: {
slug: '',
name: ''
}
}
},
methods: {
addCate () {
axios.post('http://127.0.0.1:4444/addCate', this.cate)
.then(res => {
console.log(res)
})
.catch(err => {
console.log(err)
})
}
}
11、promise
- 能够解决回调地狱的问题,可以让代码不至于嵌套很深的层次
- Promise构造函数有一个回调参数
- 回调参数有两个参数,这两个参数都是函数,一个是操作成功的回调函数resolve,一个是操作失败的回调函数reject
var p = new Promise((resolve, reject) => {
fs.readFile('./data/a.txt', 'utf-8', (err, data) => {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
var p2 = new Promise((resolve, reject) => {
fs.readFile('./data/b.txt', 'utf-8', (err, data) => {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
var p3 = new Promise((resolve, reject) => {
fs.readFile('./data/c.txt', 'utf-8', (err, data) => {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
// 2.执行promise
// then里面就传入操作成功时的回调
p
.then((res) => {
console.log(res)
// 将下一步需要执行的promise对象来返回:实现了一个链式编程
return p2
})
.then((res) => {
console.log(res)
return p3
})
.then((res) => {
console.log(res)
})
// catch中就传入操作失败的回调
.catch(err => {
console.log(err)
})
12、封装axios
方式1
在utils新建一个myaxios.js文件
import axios from 'axios'
// 设置全局的baseURL--基准路径
axios.defaults.baseURL = 'http://127.0.0.1:4444'
export default axios
import axios from '@/utils/myaxios.js'
axios({
url: '/addCate',
method: 'post',
data:this.cate
}).then(res => {
console.log(res)
})
.catch(err => {
console.log(err)
})
方式二:更简化
在api文件夹新建cate,js文件
import axios from '@/utils/myaxios.js'
export const addCate = (data) => {
return axios({
url: '/addCate',
method: 'post',
data
})
}
使用
import { addCate } from '@/api/cate.js'
------------------------------------
addCate(this.cate)
.then(res => {
console.log(res)
})
.catch(err => {
console.log(err)
})
13、路由router
路由的创建:vue创建路由
路由的跳转:<router-link to="/product">产品页</router-link>
获取路由参数:this.id = this.$route.params.id
监听路由变化:
// watch是来响应参数变化的
watch: {
'$route' (to, from) {
let id = to.params.id
}
}
路由嵌套:
{
name: 'product',
// 定义参数
path: '/product/:id',
component: Product,
// 使用children属性可以定义嵌套路由,它是一个数组,里面的每一个成员都一个单独的嵌套路由配置,每个配置都是一个对象,可以设置的成员与之前的路由配置完全一致
children: [
{
name: 'fu',
path: 'fu',
component: Fu
},
{
name: 'dian',
path: 'dian',
component: Dian
},
{
name: 'shui',
path: 'shui',
component: Shui
}
]
}
编程式导航:
// 实现编程式导航
jump () {
if (this.id === '1') {
// 会将当前路由所映射的组件加载到当前父容器的router-view
// this.$router.push({ path: `/product/${this.id}/fu` })
this.$router.push({ name: 'fu' })
} else if (this.id === '2') {
this.$router.push({ name: 'dian' })
} else if (this.id === '3') {
this.$router.push({ name: 'shui' })
}
}
14、父组件与子组件
1.添加一个单文件组件做为子组件
<template>
<div class="son">
<h2>我是子组件son</h2>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
在父组件中
// 1.引入
import son from '@/views/Son.vue'
-----------------------------
// 2.注册
components: {
son
}
-----------------------------
<template>
<div class="index">
<h1>这是index组件,它是父组件</h1>
<!-- 3.使用 -->
<son></son>
</div>
</template>
15、父子传值
父传子
父组件中为props中的成员通过动态绑定的方式赋值
<son :myname='mysonname'></son>
子组件:将这种变量定义在组件的props成员中,它一般可以定义为一个数组,里面就可以定义一个一个的变量,这种变量相当于在data中定义的变量一样来使用,props是一个单独的结构
export default {
// 这种成员可以像data中定义的成员一样来使用,只是如果是数组的定义方式,不好设置默认值
props: ['myname'],
data () {
return {
// myname: '??'
}
}
}
子传父
1.在子组件中发射事件,传递数据,通过this.$emit(自定义的事件名称,传递的数据)
2.在父组件中使用子组件的位置,监听子组件发射的事件并进行处理
// 子组件添加按钮事件
<button @click="tellname">单击告诉我老爸我的女朋友的名字叫:{{mygfname}}</button>
// 子组件的按钮事件中发射事件,并传递数据
methods: {
tellname () {
// 发射事件.$emit可以发射事件,并传递参数
// this.$emit(自定义的事件名称,传递的数据)
// this发射的事件,只能由父组件进行监听
this.$emit('getname', this.mygfname)
}
}
----------------------------------------------------
// 父组件中使用子组件的位置 监听 子组件所发射的事件
<div class="index">
<h1>这是index组件,我是父组件:{{myname}}</h1>
<h2>我的儿子告诉我他找女朋友了,名字叫:{{mysongfname}}</h2>
<!-- 3.使用 监听子组件所发射的事件,并添加事件处理函数-->
<son :myname='mysonname' @getname='dealname'></son>
</div>
// 在事件处理函数接收子组件传递的数据,并赋值给父组件中的变量,这样,父组件就有了子组件所传递的数据
methods: {
// 事件处理函数有一个默认的参数,这个参数就是子组件发射事件时所传递的数据
dealname (data) {
// 对父组件中的成员赋值
this.mysongfname = data
}
}
16、插槽
这是子组件
<div class="right">
<!-- 定义插槽:插槽可以认为是一个结构的占位,后期你可以往这个插槽中添加任意的结构 -->
<!-- 使用slot就可以定义插槽 -->
<!-- 1.匿名插槽,插槽没有定义名称,那么后期在组件使用时的所有内容都会添加到匿名插槽中 -->
<!-- <slot>默认</slot> -->
<!-- 2.具名插槽:为插槽定义名称,后期组件使用时的结构可以指定添加到哪一个插槽中 -->
<slot name='rightT'>aa</slot>
</div>
这是父组件
<mynavbar title='父子组件的传值'>
<!-- 在使用带插槽的组件时,在组件内部添加的结构默认都会添加到插槽中 -->
<span slot='leftT' @click='$router.back()'>返回</span>
<span slot='rightT'>搜索</span>
</mynavbar>
17、生命周期
vue 的⽣命周期是: vue 实例从创建到销毁,也就是从开始创建、初始化数据、编译模板、挂载Dom!渲染、更新!渲染、卸载等⼀系列过程。
18、导航守卫
导航守卫仅仅是判断能不能进行路由的跳转,并不参与请求api的合法性
在router中的index.js文件中设置
// 添加导航守卫
// to:目标路由对象
router.beforeEach((to, from, next) => {
// 只有访问那些需要授权的api的时候,才需要进行守卫
if (to.path.indexOf('/personal/') === 0) {
// 判断当前用户是否登陆过
let token = localStorage.getItem('heima_40_token')
if (token) {
next()
} else {
next({ name: 'login' })
}
} else {
next()
}
})
19、拦截器
添加请求拦截器,在拦截器进行token的值的传递
// 添加请求拦截器
// config:相当于当前的请求报文
axios.interceptors.request.use(function (config) {
console.log(config)
// 在发送请求之前做些什么:获取token,判断是否成功的获取,如果有token则添加请求头的设置,否则不处理
let token = localStorage.getItem('heima_40_token')
if (token) {
config.headers.Authorization = token
}
return config
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error)
})
转载:https://blog.csdn.net/weixin_44289670/article/details/104779754