作者: 尤雨溪
渐进式 的 自底向上增量开发的 mvvm框架
渐进式 可以和多种框架进行合并 vue是一个渐进式的框架(vue只会按照程序员的需要来进行功能的实现 不会影响到项目中没有用到vue框架的区域)只会做职责以内的事情
自底向上增量开发:先完成最基本的页面 然后再使用vue进行数据的绑定 一步步完成整个项目
MVVM
M model 模型----》就是存储变量数据的地方
V view 视图----》页面 html所写的那些东西
VM viewModel 视图模型----》就是页面与数据之前桥梁
1、获取vue库文件(使用npm(包管理工具)来进行获取)
(1)在你要写项目的文件夹 上打开cmd
(2)初始化 npm init -y
(3) 下载 npm install --save xxx (默认最新版 指定版本 npm install --save xxx@你的版本)
如果太慢 可以切换成淘宝镜像
安装:npm i -g cnpm --registry=https://registry.npm.taobao.org
(4)开始编写vue的helloword
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<h1>{{text}}h1>
<h1>{{obj.name}}h1>
div>
<script>
// 3。vm层创建(就是vue实例)
new Vue({
// 4.创建m层数据
data:{
text:"你好",
num:18,
bool:true,
arr:[111,223,444,555,6,6,7,7],
obj:{
name:"xixi",
age:18
}
},
// 5.关联视图层
el:"#demoDiv"
})
script>
body>
html>
el:创建的vue实例
就是把模型数据插入到视图中
语法:
{{表达式}}
表达式: 通过计算返回结果的公式
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.js"> script>
head>
<body>
<div id="demoDiv">
<h1>{{}}中不建议复杂的内容h1>
{{num+demo}}
<h1>{{bool?"你好":"你坏"}}h1>
<h1>{{text}}h1>
<h1>{{text.toUpperCase()}}h1>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
num:2,
demo:3,
bool:false,
text:"abcdefghijk"
}
})
script>
body>
html>
我们只需要告诉程序你要干什么 他就会自动完成
在js中我们使用的所有变量的插入页面的过程 就是命令式 我们需要指挥程序一步步干什么
传统的css就属于命令式渲染,效率较低
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<h1 id="demoh">h1>
<script>
let text="你好"
document.getElementById("demoh").innerHTML=text
script>
body>
html>
vue就是一个js框架 作用就是把数据用更加简单的方式插入到页面中 vue可以根据数据的改变让页面也随之发生改变
在vue中带有v-前缀的html特殊属性
指令的作用:是给html添加特殊的功能
语法:写在html的开标签中 v-指令=“指令值”
作用: 给表单元素进行数据绑定的
语法:v-model=“变量”
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.js"> script>
head>
<body>
<div id="demoDiv">
<h1>v-modelh1>
<input type="text" v-model="text"/>
<em>{{text}}em>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
text:"你好"
}
})
script>
body>
html>
原理:数据劫持与发布者订阅者模式
数据劫持:数据拦截 vue中使用Object.defineProerty() 就是可以监听着我们data中的模型数据 当数据改变的时候 Object.defineProerty() 就会触发 模型改变 他会通知视图改变 视图改变 就会通知模型进行改变 会监听着改变 与修改。
发布者订阅者模式:就是一个一对多的关系 发布者变了 所有的订阅者都会随之发生改变
作用: 就是控制元素的显示和隐藏
语法:v-show=“布尔值” true显示 false隐藏
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.js"> script>
head>
<body>
<div id="demoDiv">
<h1>v-showh1>
<h1 v-show="bool">控制我的显示和隐藏h1>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
bool:false
}
})
script>
body>
html>
作用:就是给dom元素绑定事件
语法: v-on:事件(不加on)=“函数” v-on:click=“fun()” v-on:change=“fun()”
简写语法: @事件=“函数”
函数写在那?
函数写在与el data 同级的位置 使用methods进行包裹
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="node_modules/vue/dist/vue.js"> script>
head>
<body>
<div id="demoDiv">
<h1>v-onh1>
<button v-on:click="fun()">点我打印内容button>
<button @click="funb()">简写button>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
},
methods:{
fun(){
console.log("你好")
},
funb(){
console.error("你坏")
}
}
})
script>
body>
html>
作用:遍历data中的数据
语法:v-for="(遍历的值,遍历的下标) in 要遍历的数据名字"
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<h1>v-forh1>
<ul>
<li v-for="(v,i) in arr">
{{v}}------{{i}}
li>
ul>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
arr:["EZ","MF","NOC","VN"]
},
methods:{
}
})
script>
body>
html>
遍历复杂数据
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<h1>v-forh1>
<ul>
<li v-for="(v,i) in arr">
{{v}}------{{i}}
li>
ul>
<hr/>
<table border="1">
<tr v-for="(v,i) in obj">
<td>{{v.name}}td>
<td>{{v.age}}td>
tr>
table>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
arr:["EZ","MF","NOC","VN"],
obj:[
{name:"huanghuang",age:27},
{name:"bilin",age:29},
{name:"xixi",age:26}
]
},
methods:{
}
})
script>
body>
作用: 给html的标签属性插入变量
语法: v-bind:html的属性=“变量” 简写 :html的属性=“变量”
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<h1>v-bindh1>
<a v-bind:href="ahref">{{text}}a>
<a :href="ahref">{{text}}a>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
text:"点我去百度",
ahref:"http://www.baidu.com"
},
methods:{
}
})
script>
body>
html>
作用:判断dom是否加载
语法: v-if=“布尔值” true加载 false不加载
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<h1>v-ifh1>
<input type="checkbox" v-model="bool">
<h1 v-if="bool">我是测试v-if的h1>
<h1 v-show="bool">我是测试v-show的h1>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
bool:true
},
methods:{
}
})
script>
body>
html>
v-if 是对dom元素进行添加和移除 v-if 在加载的时候对性能损耗低 v-if在元素频繁切换的时候性能损耗高
v-show 是对dom元素使用css进行显示和隐藏 v-show 在加载的时候对性能损耗高 v-if在元素频繁切换的时候性能损耗低
作用: v-if不符合的时候执行else
语法:必须配合v-if来进行时候用 不能单独使用
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<h1>v-elseh1>
<input type="checkbox" v-model="bool">
<h1 v-if="bool">你好h1>
<h1 v-else>你坏h1>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
bool:true
},
methods:{
}
})
script>
body>
html>
作用 可以对多个内容进行dom添加的判断
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<h1 v-if="num==1">吃h1>
<h1 v-else-if="num==2">睡h1>
<h1 v-else-if="num==3">上厕所h1>
<h1 v-else-if="num==4">在睡h1>
<h1 v-else>什么也没有干h1>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
num:8
},
methods:{
}
})
script>
body>
html>
作用:在网页中展示纯文本内容 同{{}}类似的功能
语法: v-text=“变量”
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<h1>v-texth1>
<h1>{{demo}}h1>
<h1 v-text="demo">h1>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
demo:"我是文本"
},
methods:{
}
})
script>
body>
html>
相同点: 都可以向页面中插入内容
不同点:{{}}模板插值的语法 而v-text是指令
v-text可以解决屏幕闪烁问题
当用户网络很慢的时候 由于js没有加载 可能会导致页面出现{{}} 问题 然后js加载成功之后 {{}}消失变成正常的数据展示 可能会在成用户体验不好
解决:
1.使用v-text
2.使用v-cloak指令来解决 当前这个指令的作用是保持元素上直到关联vue实例之后 在进行编译
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
<style>
[v-cloak]{
display: none; //解决屏幕闪烁问题
}
style>
head>
<body>
<div id="demoDiv" v-cloak>
<h1>v-texth1>
<h1>{{demo}}h1>
<h1 v-text="demob">h1>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
demo:"我是文本1",
demob:"我是text"
},
methods:{
}
})
script>
body>
html>
作用:把字符串标签插入页面进行展示
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<div>
{{text}}
div>
<div v-text="text">
div>
<div v-html="text">div>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
text:"我是斜体"
},
methods:{
}
})
script>
body>
html>
作用:一次性插值
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<input type="text" v-model="text">
<h1>{{text}}h1>
<h1 v-once>{{text}}h1>
<h1>{{text}}h1>
div>
<script>
new Vue({
el:"#demoDiv",
data:{
text:"你好么么哒"
},
methods:{
}
})
script>
body>
html>
监听data中的数据,如果数据改变了,watch就会收到通知,调用一个函数。(我们就可以在这个函数中完成指定的逻辑)
语法:whtch写在与 el data methods同级
watch:{
要监听的数据名(新数据名,旧数据名){
函数(需要做的事情) }
}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="./node_modules/vue/dist/vue.js">script>
head>
<body>
<div id="demoDiv">
<input type="text" v-model="inputval">
div>
<script>
new Vue({
el:"#demoDiv",
data:{
inputval:""
},
methods:{
},
// 监听
watch:{
inputval(newval,oldval){
console.log(newval+"----"+oldval)
}
}
})
script>
body>
html>
首次加载不会触发
首次加载执行函数需通过其immediate 属性进行配置,默认为false
监听数组值变化需通过其deep属性进行配置,默认为false
watch:{
"aaa":{
immediate:true, // 首次加载的时候执行函数
deep:true, // 深入观察,监听数组值,对象属性值的变化
handler:function(){
}
}
1.必须有node
2.切换淘宝镜像 npm i -g cnpm --registry=https://registry.npm.taobao.org
3.全局下载脚手架 npm install -g @vue/cli
(只需要下载一次)
4.查看版本 vue --version
5.创建项目
5.1 在项目所在路径打开cmd
5.2 在打开的cmd里输入 vue create 项目名
(选择第三个 手动选择)
6.启动项目
6.1 cmd里cd到项目所在路径
6.2 cmd里输入 npm run serve
1.查看项目文件夹中是否存在 node_modules?如果没有,在cmd里cd到当前项目路径 使用 npm install
重新下载依赖
2.在项目目录下找到package.json文件,在文件中查看scripts节点
所有的命令都需要使用npm run 配置项
(有一个特例 npm start)
1.删除src下commponents文件夹的helloworld.vue文件
2.删除src下app.vue的内容
3.VSCode里下载插件:vetur
4.在src下的commponents中新建.vue文件
5.在app.vue中引用自己创建的.vue文件
.vue文件有三部分
template部分 就是今后写html的地方
你好
//style部分 CSS
{{text}}
JavaScript中的对象是引用类型的数据,当多个事例引用同一个对象时,一个实例对这个对象进行操作,其他实例中的数据也会发生变化
在vue中,为了使每个组件都有自己的数据空间,不干扰其他组件的运行,就把他写成函数的形式,数据以函数返回值的形式定义,当我们每次复用组件的时候,就会返回一个新的data。
与本地模式写法相同
{{text}}
与本地模式写法相同
{{text}}
谁触发这个事件 事件对象就是谁
事件对象
vue中对于事件上面添加了一个新的内容修饰符,通过修饰符可以对当前这个事件来设置更多辅佐性的功能
语法:v-on: 或@事件.修饰符="函数"
对键盘上面的按键进行指定
.up .down .left .right .ctrl .enter .space
使用修饰符来完成对于指定按键的设置
阻止冒泡 | .stop |
---|---|
阻止默认行为 | .prevent |
设置捕获(与事件冒泡相反) | .capture |
只触发一次 | .once |
只触发自己范围内的事件,不包含子元素的 | .self |
修饰符同时可以串联
阻止冒泡
vue的属性 这个属性是有计算功能的(对data数据进行计算展示)
语法:写在与data methods等同级位置
一条数据 在多个位置 以不同形态展示的时候 可以使用计算属性computed
一个变量 在显示之前 进行数据处理 也可以使用计算属性computed
computed:{
计算出的结果变量(){
return 计算内容
}
}
数组字符串截取时
splice不可使用 会报错。splice会对改变原数组
slice 可以使用 slice不会对原数组产生影响
正常展示:{{text}}
大写展示:{{textUpper}}
大写加截取展示:{{textSub}}
你好
{{newarr}}
{{fun()}}
计算属性走缓存,只要计算属性处理过数据之后,数据在没有改变的时候,无论在页面调用多少次,它都只执行一次,剩下的调用都是从缓存中进行读取的,节省资源。
函数(方法)只要被调用就会执行,调用多少次就会执行多少次,比较消耗资源
计算属性与监听都是对data的数据进行相关的操作
计算属性是依赖data的数据,并且对data的数据进行处理并把处理后的结果返回
监听仅仅是监听,当data的数据改变时它会触发一个函数,来完成一些逻辑
axios是一个基于promise的第三方数据请求库
下载:npm insatll --save axios
axios的基本使用
上面代码有跨域问题,会出现如下错误
浏览器的安全机制,不同源(不同端口 不同协议 不同域名)就会造成跨域
1.jsonp(面试会问,工作不用)
2.代理跨域
devServe代理跨域
nginx反向代理
3.cors
代理跨域:
devServe代理跨域
方式:
1.需要在vue项目的根目录下创建一个vue.config.js
文件
2.在vue.config.js
文件中写以下内容:
module.exports={
devServer:{
proxy:{
"/api":{
target:"http://www.weather.com.cn/",
changeOrigin:true,
pathRewrite:{
"^/api":""
}
}
}
}
}
3.【重要】修改项目的请求路径为/api
4.因为上一步修改了配置文件,项目必须重启(重新npm run serve)
在发送请求的时候,在项目中 每次请求都要携带一些参数数据的时候,可以使用拦截器,把每次发送请求时需要携带的数据,使用拦截器先拦截下来 添加要携带的参数,再发送出去,减少代码重复编写。
拦截器分为两种:
1.请求拦截
2.响应拦截(404或其他拦截错误时给用户作出相应提示)
使用:
1.在项目的src文件夹
下新建两个文件夹 :
api
===存储数据请求封装
util
===存储工具库的
2.创建拦截器 在util文件夹
下新建service.js文件
,写以下内容:
import axios from "axios"
// 创建axios实例
let service=axios.create()
// 设置拦截器
// 添加请求拦截器
service.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
service.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
export default service
import axios from "axios"
// 创建axios实例
let service=axios.create()
// 设置拦截器
// 添加请求拦截器
service.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
service.interceptors.response.use(function (response) {
// 对响应数据做点什么 当相应成功正确的时候你所写的地方
return response;
}, function (error) {
console.log("http状态吗",error.response.status)
switch (error.response.status) {
case 404:
alert("哎呀网络连接超时!!!!")
break;
case 500:
alert("当前服务器正在维护请您稍后再试")
break;
default:
alert("您的错误反馈后台技术已经接收 请您稍后在次访问此页面!")
break;
}
// 对响应错误做点什么
return Promise.reject(error);
});
export default service
就是在发送请求的时候 会先经过他 可以在请求拦截里面添加每次发送请求都要携带的参数
1.在src/api文件夹
下创建一个getapi.js文件
封装数据请求
import service from "@/util/service.js"
// 开始封装数据请求
function getlink(url){
return new Promise((resolve,reject)=>{
// 开始写你的数据请求
service.request({
url,
method:"GET"
}).then((ok)=>{
resolve(ok)
}).catch((err)=>{
reject(err)
})
})
}
export default getlink
2.调用数据请求
1.下载 npm install --save mockjs
2.在src文件夹
下创建一个mock文件夹
(用来存放模拟数据的文件夹)
3.编写模拟数据json与mock配置
3.1在src/mock文件夹
下创建.json文件
用来编写模拟数据
3.2配置模拟数据==在mock文件夹
里新建index.js文件
// 1.引用mockjs
let Mock=require("mockjs")
// 2.配置
// Mock.mock("模拟数据地址","方式get/post",require("你的json数据"))
Mock.mock("/data/list/xiaoming","get",require("./data.json"))
4.在main.js
里使main.js和mockjs建立关联
import Vue from 'vue'
import App from './App.vue'
// 1.引用组件
import Ceshi from "./components/ceshi.vue"
// 2.配置成为全局组件
// Vue.component(给你引用的组件起个调用名,你引用的组件)
Vue.component("Ceshi",Ceshi)
// 建立mock与项目的关系
// 因为如果我们只写了文件夹的地址 那么他会自动找到这个文件夹的index
// .js
require("./mock")
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
get请求 发送数据使用params发送
使用data
发送数据需要进行转换
post发送数据需要进行转换URLSearchParams( )之后 后台才能正常接收到数据
fun(){
// 发送post需要使用
let usp= new URLSearchParams()
// 每条数据都需要使用append进行绑定
// usp.append(你要发送数据的key,val)
usp.append("uname",this.inputaval)
usp.append("upwd",this.inputbval)
link("/api/niubi_userlist/user/denglu","post",{},usp).then((ok)=>{
console.log(ok)
})
}
}
1.根目录下新建vue.config.js文件
moudle.exports={
devServer:{
// 自动开启
open:true,
port:8888//修改端口号 手动指定端口号
}
}
在项目的根目录下vue.config.js文件中
module.exports={
devServer:{
open:true
},
// 配置引用别名
configureWebpack:{
resolve:{
alias:{
// 别名:真实路径
"niubi":"@/utils"
}
}
}
}
组件自定义控件(通过组件可以把一个页面拆分成一个个小UI模块,然后把它们拼装到一块形成一个完整的页面)
通过组件,创建出可复用的UI代码块
组件的本质:自定义标签(单标签,双标签均可)
只能在部分地方使用
1.在src下的components文件夹
中创建对应的组件.vue
文件并且编写内容
2.显示组件【在APP.vue中进行】(默认情况下 只创建组件 是不会在页面显示的)
(1)引用(import from)
(2)调用(components+组件名)
在data、methods的同级位置 创建components:{调用的组件}
(3)使用
可以在项目的任何地方使用(想过想在多个地方使用某组件,可以把这个组件变成全局组件)除非前期设计好组件的使用,否则建议少用全局组件(全局组件名会造成项目的污染)
1.在main.js
中进行引用和配置
import Vue from 'vue'
import App from './App.vue'
// 1.引用组件
import Ceshi from "./components/ceshi.vue"
// 2.配置成为全局组件
// Vue.component(给你引用的组件起个调用名,你引用的组件)
Vue.component("Ceshi",Ceshi)
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
2.在想使用全局组件的地方直接用
比如想在a.vue组件中使用,在页面如下位置引入
链接栏
各组件之间样式互不干扰
使用scoped后,当前样式仅对当前组件生效
组件与组件之间是可以相互嵌套的,这种嵌套关系就是父子组件
父组件的数据子组件不能直接用
子组件的数据父组件不能直接用
组件与组件之间是一个完整的独立的个体,数据与数据之间默认是不能相互直接使用的
props是一个属性
1.在子页面中 data methods同级使用 props:[接收父组件传值的变量1,接收父组件传值的变量2,接收父组件传值的变量3,接收父组件传值的变量.......]
zizizizziizz
2.在子组件中进行使用
zizizizziizz----{{zitext}}
3.父组件传值
===变量加v-bind(:),字符串不加v-bind,直接 zitext="字符串内容"===
props验证,在传统的props验证的写法中,我们可以给子组件传递任何数据类型的数据
但是在一些特殊情况下这样可能会出问题(如果子组件拿到数据需要对数据进行操作的时候,可能不同的数据类型所展示的结果就会出现偏差)
props验证如果不成功,不会影响页面的展示,只会在控制台给出一个警告提示
语法:
1.在data methods等同级位置
export default {
props:{
要接收的变量:数据类型//Number 数字类型、String 字符串类型、 Boolean 布尔类型
}
}
zizizziziziziziziz---{{title+6}}
2.使用
3.传递
同基本写法
逆向传值默认不允许,想进行逆向传值的话,必须通过事件来触发传递
1.在子组件中创建一个事件触发一个函数,进行逆向传值的准备
zizizizizzi
2.在子组件中抛出子组件要传递的数据===把数据绑定到自定义事件之上
自定义事件: this.$emit(“自定义事件的名字”,“数据”)
zizizizizzi
3.父组件接收子组件抛出的数据===接收自定义事件使用数据
fyufufufff
只需要在组件之上使用ref即可直接取出子组件的数据
在同一父组件下的子组件进行相互数据传递
中央事件总线(eventBus):凌驾于两个兄弟组件之上的一个空的vue实例
1.在src文件夹
下创建eventBus文件夹
(容纳中央事件总线的文件夹),新建index.js文件
// 容纳中央事件总线
import Vue from "vue"
export default new Vue
2.在要传递的组件(src/components/里面的组件文件)上抛出
ziaaaaaaaaaaaaaaaaaaaaaa
3.在要接收的组件中接收
zizizizizizbbbbbbbbbbbbbb
vuex:状态(数据)管理工具
vuex可以把整个项目的数据集中地管理起来,方便组件与组件的使用(组件想使用数据, 不需要使用复杂的传递方式了,直接去vuex中进行数据的获取)
传统的vue是单向数据流,如果是兄弟或者是跨层级的组件在进行传递的时候,vue就非常麻烦,vuex就可以进行上述传递,简化了数据传递的复杂度
src/store文件夹
用来容纳vuex的文件夹
1.下载 npm install --save vuex
2.在src文件夹下新建store文件夹 并且新建index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
})
3.在main.js中引用vuex文件 并且在vue实例上注册
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'//引用
Vue.config.productionTip = false
new Vue({
router,
store,//注册
render: h => h(App)
}).$mount('#app')
vuex的所有数据都在state中进行创建
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {//创建数据的类似于组件中的data
text:"你好",
age:18,
arr:[111,2222,33333],
obj:{
love:"女"
}
},
mutations: {
},
actions: {
},
modules: {
}
})
1.取值方式一
任意组件想要使用数据,使用this.$store.state.xxx
hhhhh{{this.$store.state.text}}
2.取值方式二
计算属性computed
防止数据没有请求到的时候页面会报错
uuuuu{{newage}}
vuex中state的数据不能直接修改
mutations里面封装的是一个个函数,每个函数就是一个修改的动作
如果要触发mutations的修改动作 我们要使用commit这个方法来进行调用commit触发mutations修改
1.通过事件触发commit来调用修改操作
hhhhh{{this.$store.state.text}}
2.去store中编写对应的mutations修改动作
mutations: {
uptext(){
}
},
3.开始修改
mutations: {
// 第一个形参state就是指向上面的state数据源
// 第二个形参接收的就是commit方法中的第二个参数
uptext(state,payload){
state.text=payload.newtext
}
},
在vuex中如果修改数据之后,页面刷新一次,那么页面的数据会恢复成默认值。
解决方法:在页面刷新的时候,把vuex里的数据转成字符串,转成对象,存储到本地,页面刷新后,将本地存储的数据重新渲染到页面中
created() {
//在页面加载时读取sessionStorage里的状态信息
if (sessionStorage.getItem("store")) {
this.$store.replaceState(
Object.assign(
{},
this.$store.state,
JSON.parse(sessionStorage.getItem("store"))
)
);
}
//在页面刷新时将vuex里的信息保存到sessionStorage里
window.addEventListener("beforeunload", () => {
sessionStorage.setItem("store", JSON.stringify(this.$store.state));
});
},
actions是一个触发器,可以帮我们触发一个异步操作(异步请求)
actions中一个个方法,每一个方法就是一个异步的动作
actions调用的话,使用dispatch()调用
1.页面通过dispatch来触发actions
ppppp{{this.$store.state.text}}
actions创建对应的方法
actions: {
// context形参 就是store对象
demoLink(){
console.log("我是actions")
}
},
//
created(){
// 2.通过dispatch触发一个actions
this.$store.dispatch("getaxios",{url:"/data/one"})
}
3.编写对应的actions
actions: {
// 3编写对应的actions
getaxios(){
}
},
4.引用数据请求 并且发送
import Vue from 'vue'
import Vuex from 'vuex'
// 4.引用数据请求
import getlink from "@/apis/getapi.js"
Vue.use(Vuex)
export default new Vuex.Store({
state: {//创建数据的类似于组件中的data
},
mutations: {
},
actions: {
// 3编写对应的actions
getaxios(context,payload){
console.log(context)
// 5.发送一部操作
getlink(payload.url).then((ok)=>{
console.log(ok)
})
}
},
modules: {
}
})
actions: {
// 3编写对应的actions
getaxios(context,payload){
console.log(context)
// 5.发送一部操作
getlink(payload.url).then((ok)=>{
console.log(ok.data.data)
// 6.把请求来的数据交给mutations来修改state
context.commit("uparr",{arrdata:ok.data.data})
})
}
},
7.创建对应的mutations
// 7创建对应的mutations
uparr(state,payload){
// 8把请求来的数据修改state
state.arr=payload.arrdata
}
在页面展示
-----
{{newarr}}
getters可以对一个数据在不同位置展示出不同的形态使用
getters处理的数据 任何组件都能用
vue的计算属性处理的数据只能当前组件使用
定义getters
getters:{
// 里面就一个形参 state代表的就是数据源
newdemo(state){
return state.demo.toUpperCase()
}
}
使用
在想使用的地方直接使用 this.$store.getters.xxx(getters里的函数名)
即可获取到处理好的数据
可以把原来写在一起的数据 修改 异步操作 计算属性 按照页面等进行分类管理
1.新建文件用来单独放置上述的属性
let userm={
state: {
text:"我是user的数据"
},
mutations: {
},
actions: {
},
getters:{
},
}
export default userm
2.把模块注入到vuex中
import Vue from 'vue'
import Vuex from 'vuex'
// 引用模块
import Homem from "./modules/homem.js"
import Phonem from "./modules/phonem.js"
import Userm from "./modules/userm.js"
Vue.use(Vuex)
export default new Vuex.Store({
// 注入
modules: {
Homem,
Phonem,
Userm
}
})
3.使用数据 this.$store.state.模块名.xxx
用来混合父组件和子组件自己的模板(就是可以在组件被调用的时候向其内部插入新的dom节点)
使用方法:
1.在要抛出的组件使用:
2.在要接收的组件使用:
如果调用的时候组件使用的是双标签,默认情况下不能在他的开关标签中插入新的内容
fufufuffufu
这个h1是不会显示的
你好么么哒!!!!^_!
在你想插入新内容的组件中,放置一个 ,外部的内容就会显示在slot插入的位置
槽口虽然只有一个 但是外部插入的所有内容都在这一个上面显示 后期不好管理
ziziziziz
1.定义槽口的时候 使用name创建槽口的名字
2.插入的时候需要指定往那个槽口插入 使用slot属性
fufufuffufu
你好么么哒!!!!^_!1
你好么么哒!!!!^_!2
你好么么哒!!!!^_!3
你好么么哒!!!!^_!4
你好么么哒!!!!^_!7
你好么么哒!!!!^_!8
为我们完成页面之间的跳转,让我们完成单页面多视图的应用(SPA)
vue-router库来实现路由
1.下载vue-route库
2.创建views文件夹 并写入路由页面组件
3.配置路由规则
3.1新建router文件夹 并新建index.js文件
3.2在index.js文件中
import Vue from 'vue'//引用vue
import VueRouter from 'vue-router'引用vuerouter
Vue.use(VueRouter)在vue中使用路由功能
创建了路由规则配置
const routes = [
{
path: '/home',
name: 'Home',
component: Home
},
]
实例化路由对象 并且设置路由模式与路由规则的传入
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
暴露
export default router
4.注入路由 main.js文件中注入
import Vue from 'vue'
import App from './App.vue'
import router from './router' 引用路由
Vue.config.productionTip = false
new Vue({
router,注入路由
render: h => h(App)
}).$mount('#app')
在创建vue脚手架项目的时候 要选中router项
在项目创建好之后 src文件夹下多了两个文件夹
views
===页面文件夹
router
===配置路由的
1.在/src/views文件夹
下创建对应页面
2.配置路由页面规则 /src/router/index.js
中进行配置
import Vue from 'vue'
import VueRouter from 'vue-router'
// 1.引用路由页面到路由规则配置文件中
import Home from '../views/home.vue'
import Gouwu from '../views/gouwu.vue'
import Jingxi from '../views/jingxi.vue'
import Fenlei from '../views/fenlei.vue'
import Wode from '../views/wode.vue'
// 在vue中使用路由功能
Vue.use(VueRouter)
// 2、配置路由规则
const routes = [
{
path: '/',//url路径
name: 'Home',//给当前的规则起个名字
component: Home //你匹配的路由页面
},
{
path: '/gouwu',//url路径
name: 'gouwu',//给当前的规则起个名字
component: Gouwu //你匹配的路由页面
},
{
path: '/fenlei',//url路径
name: 'fenlei',//给当前的规则起个名字
component: Fenlei //你匹配的路由页面
},
{
path: '/jingxi',//url路径
name: 'jingxi',//给当前的规则起个名字
component: Jingxi //你匹配的路由页面
},
{
path: '/wode',//url路径
name: 'wode',//给当前的规则起个名字
component: Wode //你匹配的路由页面
},
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
3.设置路由出口,在app.vue中 使用router-view
进行标识
router-link来进行页面的切换 其中to属性来设置跳转地址
在vue路由导航中 会默认给我们选中的当前导航添加样式类 router-link-active
如果在配置路由的时候,路由规则的path中,有单独的/ ,那么无论是否选中当前这个路由,都会添加相应的类名。解决方法:在配置路由的时候,path中不设置单独 /
但是如果在设置路由规则path的时候,没有设置单独的 / 那么第一次进入页面的时候就没有默认路由规则,也就是没有默认的首页,解决方式就是使用重定向
this.$router.push("/要跳转的页面")
404页面
this.$router.replace("/要跳转的页面")===不能回退,付款等页面使用
this.$router.go( ) 正数-前进 负数-回退
重新定位方向 可以在第一次进入页面的时候帮助用户自动把页面进行指定为位置的切换
const routes = [
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/shop',
name: 'shop',
component: Shop
},
{
path: '/phone',
name: 'phone',
component: Phone
},
{
path: '/user',
name: 'user',
component: User
},
// 重定向
{
path:"/",
// 重新定位方向
redirect:"/home"
}
]
url中出现了没有配置过得路由页面,就会出现白屏
解决方法:需要给用户没有在url中没有配置过路由的情况下, 作出一个页面没有找到的提示
404页面必须在路由规则的最下面 就算有重定向也要在它下面
const routes = [
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/shop',
name: 'shop',
component: Shop
},
{
path: '/phone',
name: 'phone',
component: Phone
},
{
path: '/user',
name: 'user',
component: User
},
// 重定向
{
path:"/",
// 重新定位方向
redirect:"/home"
},
// 404页面必须在路由规则的最最最下面 就算有重定向也要在他下面
// 404页面必须在路由规则的最最最下面 就算有重定向也要在他下面
{
path: '*',
name: 'no',
component: No
}
]
在一个路由中嵌套另外一个路由就叫多级路由
(1)在views文件夹创建一级界面文件,在views/二级路由文件夹创建二级界面文件
(2)一级页面写 1.写切换的页面 2.router-view路由出口
切换页面1
切换页面1
//路由出口
(3)在router/index.js文件中 先在顶部import引入一级和二级页面。给一级路由添加children属性,把二级页面添加进去
使用children关键字进行配置
1.在views文件夹下 新建二级路由页面
2.配置路由规则
2.1在router文件夹下的index.js中引用二级路由页面
2.2在要添加二级路由的一级路由的配置页(router/index.js)中配置二级路由
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/home.vue'
import Sj from '../views/shiji.vue'
import Syy from '../views/shuyingyin.vue'
import Wode from '../views/wode.vue'
import Xz from '../views/xiaozu.vue'
// 1.引用二级路由页面
import Era from "@/views/er/era.vue"
import Erc from "@/views/er/erc.vue"
import Erd from "@/views/er/erd.vue"
import Ere from "@/views/er/ere.vue"
Vue.use(VueRouter)
const routes = [
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/sj',
name: 'Sj',
component: Sj
},
{
path: '/syy',
name: 'Syy',
component: Syy,
// 2.二级路由配置
children:[
{
path: '/era',
name: 'Era',
component: Era
},
{
path: '/erc',
name: 'Erc',
component: Erc
},
{
path: '/erd',
name: 'Erd',
component: Erd
},
{
path: '/ere',
name: 'Ere',
component: Ere
},
]
},
{
path: '/wode',
name: 'Wode',
component: Wode
},
{
path: '/xz',
name: 'Xz',
component: Xz
},
{
path:"/",
redirect:"/home"
}
// {
// path: '/about',
// name: 'About',
// // route level code-splitting
// // this generates a separate chunk (about.[hash].js) for this route
// // which is lazy-loaded when the route is visited.
// component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
// }
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
3.在对应一级页面中,使用配置二级路由出口
书影音
4.设置路由导航
4.1如果多级路由在配置规则(index.js)的时候,path带 / - path: “/xxx” 那路由导航()属性就是 /xxx
{
path: '/era', //path带/斜杠
name: 'Era',
component: Era
},
路由导航
<router-link to="/era">era</router-link>
4.2如果多级路由在配置规则的时候 path不带 / path:“xxx” 那么 路由导航to属性就是/一级路由/二级路由
{
path: 'era', //path不带/
name: 'Era',
component: Era
},
路由导航
<router-link to="/syy/era">era</router-link>
在vue设置路由的时候,有两种模式:hash、history
在main.js
中使用mode来设置
mode: 'history',
区别 | hash(默认值) | history |
---|---|---|
url展示上 | url带# | url不带# |
兼容性 | 支持低版本浏览器 | 是HTML5新增的所以不兼容低版本浏览器 |
刷新页面(上线之后) | 刷新正常 | 刷新页面会丢失 |
在开发APP分享页面的时候,如果这个页面就是vue写的,在嵌入到第三方原生app 的时候,有的app对url有要求,不能带#
把数据从一个路由页面传递到另外一个页面的技术
1.在路由规则中设置接收参数(谁接收数据,就在谁的路由规则中配置)
{
path: '/xz/:xiaoming',//接收数据的规则上设置接收参数
name: 'Xz',
component: Xz
},
2.发送数据
this.$router.push({name:“要跳转的路由规则name”,params:{配置的接收参数:“数据”}})
fun(id){
console.log(id)
// 传递数据
// this.$router.push({name:"你要跳转的路由规则的name",params:{你配置的接收参数:"数据"}})
this.$router.push({name:"Xz",params:{xiaoming:id}})
}
3.接收数据this.$route.params.xxx
{{this.$route.params.xiaoming}}
1.发送数据
this.$router.push({name:“要跳转的路由规则的name”,query:{接收参数:“数据”}})
this.$router.push({path:“要跳转的路由的路径”,query:{接收参数:“数据”}})
// 使用query方式进行传参
this.$router.push({name:"Sj",query:{xiaohong:"我是query传参"}})
2.接收数据
this.$route.query.xxx
1.用法上:
query方式可以使用path也可以使用name作为跳转路径,params只能用name
接收上:query使用this. r o u t e . q u e r y . x x x 而 p a r a m s 使 用 t h i s . route.query.xxx 而params使用this. route.query.xxx而params使用this.route.params.xxx
2.url展示上不同
query是key=val query显示key相对来说不安全
params url只有val 不显示key 相对来说安全一些
$router 是vueRouter的全局对象里面包含了对路由全局操作的属性和方法
$route 是一个路由对象。每一个路由都有一个route对象也就是说他是类似于局部页面路由的一个对象他只能处理当前路由页面的操作
懒加载就是按需加载,在想使用的时候进行加载
就是给使用者更好的用户体验,路由的项目可能会出现首页白屏问题
路由是完成spa单页面应用的一个技术,就是项目中之后一个页面,如果用户需要切换页面显示的话,就是在当前页面对整体内容进行一个替换
项目在第一次加载的时候 会把全部页面都加载 然后把需要显示的页面显示出来,可能页面过多,导致加载事件过长,那么用户所看到的就是白屏
路由懒加载分为两种:
在router/index.js中修改,采用懒加载后头部不需要import Home from '../views/home.vue
的方式进行引用
1.vue异步组件的方式
component: (resolve) => require(['你要引用的路由页面路径'], resolve)
2.es中import的方式
component: () => import('你要引用的路由页面路径')
{
path: '/class',
name: 'Class',
component: () => import ('../views/class.vue'),
},
路由切换的时候被自动调用的函数
使用场景:vue项目中进行所在路由页面切换的时候 进行一些项目的验证,比如:用户登录的状态验证,就需要每次页面切换的时候进行状态的验证(会自动执行)
无论哪个路由 在切换到时候都会触发这个钩子函数
在router/index.js中写。写在实例化路由对象之后
// 全局前置守卫
// router.beforeEach((to去哪里,from从哪里来,next下一步)=>{})
router.beforeEach((to,from,next)=>{
console.log("to",to)
console.log("from",from)
if(to.path=="/about"){
next()
}else{
alert("您没有登录请您登录后在试!!!")
next("/about")
}
})
进入到路由的时候生效
// 全局后置守卫
// router.afterEach((to从哪来,from去哪里)=>{})
router.afterEach((to,from)=>{
console.log("to",to)
console.log("from",from)
})
相对于全局守卫来说,路由守卫仅对一个路由页面生效
router/index.js 钩子函数写在指定要设置守卫的路由配置中,与path 那么 同级
{
path: '/phone',
name: 'phone',
component: () => import( '../views/phone.vue'),
// 路由独享守卫
beforeEnter(to,from,next){
console.log(to)
console.log(from)
// 进行一些是否登录的判断判断成功让她进入 不成功不能进
alert("当前页面是vip页面")
next("/about")//不让下一步
}
},
写在指定的.vue文件中
组件内守卫
开发者可以再路由中自己添加一些数据 方便页面使用
{
path: 'erf',
name: 'erf',
component: () => import( '../views/er/erf.vue'),
meta:{
title:"账号权限"
}
},
this.$router.options.routes
mixin是vue组件复用功能的技术之一 它可以把多个组件中重复出现的属性和方法多次进行封装方便多次调用
1.混入就是把组件多次使用的属性和方法等内容进行封装
新建mixin文件夹用来容纳混入的封装
export let demo={
methods:{
fun(){
console.log("你好!!!!!!")
}
},
data(){
return {
}
},
computed:{
}
}
慎用全局混入,可能会造成代码的污染
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 1.引用mixin
import {demo} from "./mixins"
// 2.配置全局混入
Vue.mixin(demo)
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
This is an about page
生命周期 vue实例从创建到销毁的过程
钩子函数 就是特定阶段内被自动调用的函数。给开发者在程序不同阶段提供一个自动执行程序(逻辑)的场所
8个钩子函数 4组(实例创建 模板渲染 数据更新 实例销毁)
beforeCreate实例准备创建。
created 实例创建完毕。在vue实例new 创建完毕之后立即调用,但是这个时候只是把vue实例出来了,实例中的data methods等属性还没有开始处理
beforeMount模板准备渲染
mounted 页面加载完毕之后立即调用 页面已经显示了 vue实例中的内容也已经处理完了
beforeUpdata 开始准备更新
updated 更新完毕
beforeDestory 开始准备销毁
Destorted 销毁完毕
1.生命周期在页面初次加载的时候执行什么?
前两组 分别为 实例创建前后(带英文) 模板创建前后(带英文)
2.声明周期的作用是什么?
vue实例从创建到销毁的过程中在特定阶段内被自动调用的函数同时给开发者在程序的不同阶段提供一个自动执行程序(逻辑)的场所
3.vue生命周期一共几个阶段?
4大阶段 8个钩子
4.简述vue生命周期的各个钩子函数?
beforeCreate 实例准备创建(数据观测与初始化事件还没有执行)
created 实例创建完毕 (完成了诗句的观测 属性 方法也都进行了初始化 但是页面没有显示渲染)
beforeMount 模板准备渲染 (在准备吧template模板网页面中进行挂载 准备编译页面内容)
mounted 页面加载完毕之后立即调用 (页面被成功的进行了挂载 页面的dom内容也都生成完毕)
updated 更新完毕(数据已经成功的在页面dom中更新完毕了)
beforeDestory 开始准备销毁(vue实例还能用)
Destoryed 销毁完毕
5.vue数据请求应该在哪个钩子函数中进行调用,为什么?
在created和mounted中都可以
但是,如果要涉及请求完毕操作dom的时候,那么必须在mounted中进行数据请求
在不改变原始数据的情况下 格式化展示数据
1.写在与data、methods等 同级位置
filters:{
过滤器的名字(操纵的数据){
return 要做的事情===函数
}}
export default {
props:["datalist"],
// 过滤器
filters:{
xiaoming(val){
if(val.length>6){
return val.substr(0,5)+".."
}else{
return val
}
}
}
}
使用过滤器,在想使用的数据后面使用 管道符(|)+过滤器名字
在项目的根目录下vue.config.js文件中
module.exports={
devServer:{
open:true
},
// 配置引用别名
configureWebpack:{
resolve:{
alias:{
// 别名:真实路径
"niubi":"@/utils"
}
}
}
}
在给多个组件使用用一个挂载点并且动态切换(多个组件每次只显示一个并且动态的进行切换)
语法:
在页面想显示多个组件的时候会用下面的语法 来声明挂载点
phone
在动态组件中如果有多个输入框 那么我们在切换动态组件的时候会发现这些输入框的内容会丢失
在多个路由页面中如果有多个输入框 那么我们在切换路由页面的时候会发现这些驶入框的内容也会丢失
我们在路由或者是动态组件切换的时候因为 每次切换vue都会出现一个新的vue组件实例 所以会丢失
keep-alive 可以在keep-alive包裹的内容 在切换的时候把数据状态保存在内存中 防止重复的DOM渲染 减少了性能与时间上的损耗
用在动态组件之上
<keep-alive>
<component :is="com"></component>
</keep-alive>
用在路由之上 只需包裹路由的出口
<keep-alive>
<router-view/>
</keep-alive>
include 你想缓存的
可以写多个 中间用逗号隔开
exclude 你不想缓存谁
<keep-alive exclude="One,Two">
<component :is="com"></component>
</keep-alive>
有两个钩子函数 但是在写的时候一定要在被keep-alive所管理的组件中进行使用
activated 进入到被keep-alive管理的组件时候触发
deactivated 离开被keep-alive管理的组件时候触发
activated(){
console.log("进入到keep-alive管理的组件了")
},
deactivated(){
console.log("离开了keep-alive管理的组件了")
}
问题:vue数据改变页面没有改变(没有更新)的情况?
原理:当vue中data里的数据(对象和数组)在初始化完毕之后 再向其中插入新的属性的时候,这时候数据发生改变,但是页面视图不会更新
vue数据变视图不会改变-----$set
{{ obj.name }}--{{obj.age}}
在vue2.0中双向绑定使用的是数据劫持Object.defineProerty()
,但是Object.defineProerty()就监听不到 监听不到就没有数据劫持 没有劫持就没有双向绑定 所以数据变了视图也不会改变
想中途添加一个新属性并且数据变视图也要改变怎么办?
语法:this.$set(“要修改的”,“要新增的key”,“要新增的val”)
$set应用
{{ obj.text }}
set(text){
// this.$set(this.obj,"text",text);
this.$set(this.obj,"text",text);
this.obj.text="我是$set更改后的数据";
console.log(this.obj.text)
}
就是在vue中进行dom操作
user
在现有的指令不够用的时候,自己创建指令
语法:
写在与data methods同级
directives:{
自定义指令的名字:{
自定义指令的钩子函数(el 绑定的自定义指令所在的dom元素){
要操作的逻辑(函数)
}
}
}
bind:绑定指令到元素上 只执行一次
inserted:绑定了指令的元素在插入页面展示的时候调用
update:所有节点更新的时候调用
componentUpdate:指令所在组件的节点一级他自己所有的子节点全部更新了 再调用
unbind:解除指令和元素的绑定时候调用,只执行一次
directives:{//自定义指令
xiaoming:{//自定义指令的名字随便起
inserted(el){
el.style.color="red";
}
}
},
v-自定义指令的名字
This is an about page
因为浏览器的同源政策,就会产生跨域。比如说发送的异步请求是不同的两个源,就比如是不同的的两个端口或者不同的两个协议或者不同的域名。由于浏览器为了安全考虑,就会产生一个同源政策,不是同一个地方出来的是不允许进行交互的。
1.jsonp的方法(面试的时候不要先说jsonp)
2.使用CORS解决跨域,即跨域资源共享,在后端设置响应头部,加一句代码:access-control-allow-origin:"*"或者允许交互的域名。
3.vue react angular 使用本地开发者服务器代理跨域
devserver的proxy解决,在根目录下新建vue.config.js文件,修改propyTable中的target的值,就可实现用前端解决跨域。(打包上线后就废了)
测试接口:http://www.weather.com.cn/data/cityinfo/101320101.html
proxy:{
"/api(可以随便写)":{
target:"请求地址",
changeOrigin:true,
"pathRewrite":{
"^/api(和上面一样)":"/"
}
}
},
实现流程vue
1.在项目的根路径下创建vue.config.js
2.在这个文件中写入
module.exports={
devServer:{
open:true,//自动开启浏览器
port:8888, //修改端口
proxy:{
"/api":{
target:"http://www.weather.com.cn",
changeOrigin:true,
"pathRewrite":{
"^/api":"/"
}
}
},
}
}
3.修改里面的参数地址 并且 把你的/api 替换组件中的请求地址
4.重启项目
第四种,使用nginx反向代理跨域
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root dist;
index index.html index.htm;
}
#设置反向代理跨域
#设置反向代理跨域
#设置反向代理跨域
#设置反向代理跨域
#设置反向代理跨域
#设置反向代理跨域
#设置反向代理跨域
#设置反向代理跨域
location /api {
#设置代理需要重写/api
因为在开发的时候所有的接口都是以/api开头的,所以在请求代理的时候和proxyTable一样的逻辑,需要rewrite重写。
rewrite ^.+api/?(.*)$ /$1 break;
proxy_pass http://www.weather.com.cn;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
server {
listen 9999; # 监听端口
server_name localhost; # 域名可以有多个,用空格隔开
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root C:\工作\project\client_admin_system\dist; #站点根目录,即网页文件存放的根目录, 默认主页目录在nginx安装目录的html子目录。
index index.html index.htm; #目录内的默认打开文件,如果没有匹配到index.html,则搜索index.htm,依次类推
}
#ssl配置省略
location /api {
rewrite ^.+api/?(.*)$ /$1 break;
proxy_pass http://192.168.1.100:7001; #node api server 即需要代理的IP地址
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
#error_page 404 /404.html; #对错误页面404.html 做了定向配置
# redirect server error pages to the static page /50x.html
#将服务器错误页面重定向到静态页面/50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
第五种,使用otherWindow.postMessage 是html5引入的API,postMessage()方法允许来自不同源的脚本采用异步方式进行有效的通信,可以实现跨文本文档,多窗口,跨域消息传递.多用于窗口间数据通信,这也使它成为跨域通信的一种有效的解决方案.
将项目放在服务器上,在服务器上运行项目
流程:
1.基础命令:npm run build
build之后,运行打包后的文件夹 dist/index.html会发现页面什么都没有,并且console中有很多404错误,这是因为大报纸后静态资源文件路径有问题,需要修改才能正常显示
2.修改静态资源路径。在根目录下的vue.config.js文件里,增加 publicPath:"./"
module.exports={
publicPath: './'
}
3.router/index.js中将路由模式改为hash
const router = new VueRouter({
// mode: 'history',
mode: 'hash',//将路由模式改为hash
base: process.env.BASE_URL,
routes
})
Hbuilderx 新建 项目 h5+app
把build后的dist文件夹内的文件复制到hbuild新建的项目文件夹内
Nginx是一个http服务器。是一个高性能的http服务器及反向代理服务器。官方测试nginx能够支支撑5万并发链接,并且cpu、内存等资源消耗却非常低,运行非常稳定。
代理服务器,客户机在发送请求时,不会直接发送给目的主机,而是先发送给代理服务器,代理服务接受客户机请求之后,再向主机发出,并接收目的主机返回的数据,存放在代理服务器的硬盘中,再发送给客户机。
我们学习的vue的跨域 是基于脚手架内置服务器的 但是我们打包之后这个服务器就不帮助我们启动服务了 所以我们之前配置的跨域设置就作废了
1.解压出nginx得到如下内容
2.打开conf文件夹 复制一份nginx.conf文件 并且修改名字(名字随便起) 这个文件就是nginx的配置文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rivP3ZT7-1646355391623)(C:\Users\SZnAl\Desktop\9.bmp)]
3.打开Powershell cd到当前nginx路径下 输入 ./nginx.exe -c ./conf/你复制的文件名.conf 启动
4.打开浏览器输入localhost:80即可启动
记得如果修改服务器内容了 要停止之后在重新启动
打开Powershell cd到当前nginx路径下 输入 ./nginx.exe -c ./conf/你复制的文件名.conf -s stop 停止
1.把我们打包好的dist放到根路径下
2.修改我们的.conf文件
node是一个基于chrome浏览器js解析器(v8)的一个JavaScript运行环境
可以让js在脱离浏览器的情况下进行单独运行
单线程
非阻塞式IO(IO 输入输出)
事件驱动
node的一个企业级应用框架,简化了我们在创建http服务的时候的复杂度
使用:
1.npm install --save express
2.创建后台服务
// 1.引用express
let express=require("express");
// 2.初始化express对象
let app=express()
// 3.创建服务
// req 请求
// res 相应
app.get("/xiaoming/xiaohong",(req,res)=>{
res.send({msg:"我是一个后台服务"})
})
// 4.监听端口
app.listen(8888)
多个后台 接口 创建方法
let express=require("express");
let app=express()
app.get("/xiaoming/xiaohong",(req,res)=>{
res.send({msg:"我是一个后台服务"})
})
// 如果有多个接口
app.get("/xiaoming/xiaohua",(req,res)=>{
res.send({msg:"我是第二个"})
})
app.get("/xiaoming/xiaohei",(req,res)=>{
res.send({msg:"我是第三个"})
})
app.listen(8888)
非关系型数据库(NoSql数据库Not Only SQL):Mongodb、Redis
关系型数据库:MySql、SQL Server、Oracle、BD2
关系型与非关系型数据库区别
非关系型数据库非常快 稳定性不够 (没有一个正式的官方支持) 由于比较新 所以支持的特性还不够拓展是不够
1.npm安装Mongiise: npm install --save mongoose@5
2.在项目下新建db.js文件 来封装数据库连接内容
// 封装数据库连接的模块
// 1.引用mongoose
let mongoose=require("mongoose")
// 2.设置连接
mongoose.connect("mongodb://localhost:27017/xiaoming")//xiaoming是你设置的数据库
// 3.开始连接
var db = mongoose.connection;
// 4.设置错误的时候信息和连接成功的信息
db.on('error', console.error.bind(console, '连接错误'));
db.once('open', function() {
console.log("连接ok")
});
// 5.暴漏
module.exports=db
3.在创建的随便一个后台路由中引用db文件,并且调用
let express=require("express");
let app=express()
// 引用数据库连接模块
let db=require("./db")
app.get("/xiaoming/xiaohong",(req,res)=>{
// 调用数据库连接模块
db
res.send({msg:"我是一个后台服务"})
})
// 如果有多个接口
app.get("/xiaoming/xiaohua",(req,res)=>{
res.send({msg:"我是第二个"})
})
app.get("/xiaoming/xiaohei",(req,res)=>{
res.send({msg:"我是第三个"})
})
app.listen(8888)
运行时候有设置连接模式的警告
(node:11436) DeprecationWarning: current URL string parser is deprecated, and will be removed in a future version. To use the new parser, pass option { useNewUrlParser: true } to MongoClient.connect.
(Use `node --trace-deprecation ...` to show where the warning was created)
(node:11436) [MONGODB DRIVER] Warning: Current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.
根据以上提示配置连接模式
// 封装数据库连接的模块
// 1.引用mongoose
let mongoose=require("mongoose")
// 2.设置连接 设置连接模式
mongoose.connect("mongodb://localhost:27017/xiaoming",{ useNewUrlParser: true,useUnifiedTopology: true })//xiaoming是你设置的数据库
// 3.开始连接
var db = mongoose.connection;
// 4.设置错误的时候信息和连接成功的信息
db.on('error', console.error.bind(console, '连接错误'));
db.once('open', function() {
console.log("连接ok")
});
// 5.暴漏
module.exports=db
ElementUI 一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库
下载 npm i element-ui@2 -S
2 在 main.js 中写入以下内容:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
当前以及父级,html,body高度均设置 height: 100%
在调用接口的时候使用postman先检测接口是否正确
左上角新建-输入项目名称、介绍-输入地址、确认请求参数-点击send
接收前台的get请求 使用 req.query.xxxx
是一个规范 定义接口的名字或者是使用上的内容
get 方式 获取数据
post方式 发送数据
delete方式 删除数据
put方式或者patch方式 修改更新数据
能加密也能解密的字符串(通常用来保存用户的登录状态)
使用jsonwebtoken库来实现token
npm install --save jsonwebtoken
1.加密–sign()
sign(你要加密的数据,密钥)
密钥:我们自己定义一段越乱越好的乱码
2.解密–verify()
verify(你要解密的数据,密钥(必须和你加密时候的密钥相同),回调函数)
1.在登录成功之后 生成一个token 并且一并返回给前台
2.前台得到这个token存起来(本地存储 cookie)
3.每次页面切换或者是需要这个知道用户是否登录的时候 我们就把这个token取出来,并且发送给后台,后台会有一个专门解密这个token的接口来判断用户是否登陆过
4.把用户是否登录告诉前台,我们再作出对应的反应