Vue基础
# 直接取值
{{ 属性 }}
# 需要解析标签,防止XSS、CSRF攻击
<div v-html=""></div>
# 表达式
<img v-bind:src="imgSrc"></img>
或者简写
<img :src="imgSrc"></img>
#定义数据相关
data:{}
#定义v-on绑定的时间函数
methods:{}
#定义私有过滤器
filters:{}
#获取父组件传递过来的数据值
props:[]或props:{}
#进行数据的监听,当数据内容发生改变的时候执行
watch:{}
#计算输出的属性
computed:{}
# 条件
v-if : 从 dom 中删除
v-else-if :
v-else
v-show :只是不在页面显示
# 列表
v-for="todo in todos"
v-for="(todo,index) in todos" : index 为索引值
或者
v-for="todo of todos"
v-for="(todo,index) of todos"
# 事件
v-on:click 或者 @click
v-model : 实现表单输入和应用状态之间的双向绑定。可以代替输入框value
生命周期
beforeCreate
实例组件刚创建,元素DOM和数据都还没有初始化,暂时不知道能在这个周期里面进行生命操作。
created
数据data已经初始化完成,方法也已经可以调用,但是DOM未渲染。有人问了,请求都是异步的,并不会阻碍实例加载。这是我个人水平的问题,这边改正,在这个周期里面,请求因为是异步的,不会阻碍实例加载,除非是那些同步操走才会导致页面空白。这样说来,在这个周期里面进行请求,渲染速度反而会更快。
beforeMount
DOM未完成挂载,数据也初始化完成,但是数据的双向绑定还是显示{{}},这是因为Vue采用了Virtual DOM(虚拟Dom)技术。先占住了一个坑。
mounted
数据和DOM都完成挂载,在上一个周期占位的数据把值给渲染进去。可以在这边请求,不过created请求会更好一些。这个周期适合执行初始化需要操作DOM的方法。
beforeUpdate
只要是页面数据改变了都会触发,数据更新之前,页面数据还是原来的数据,当你请求赋值一个数据的时候会执行这个周期,如果没有数据改变不执行。
updated
只要是页面数据改变了都会触发,数据更新完毕,页面的数据是更新完成的。beforeUpdate和updated要谨慎使用,因为页面更新数据的时候都会触发,在这里操作数据很影响性能和容易死循环。
beforeDestroy
这个周期是在组件销毁之前执行,在我项目开发中,觉得这个其实有点类似路由钩子beforeRouterLeave,都是在路由离开的时候执行,只不过beforeDestroy无法阻止路由跳转,但是可以做一些路由离开的时候操作,因为这个周期里面还可以使用data和method。比如一个倒计时组件,如果在路由跳转的时候没有清除,这个定时器还是在的,这时候就可以在这个里面清除计时器。
Destroyed
说实在的,我还真的不知道这个周期跟beforeDestroy有什么区别,我在这个周期里面调用data的数据和methods的方法都能调用,所以我会觉得跟beforeDestroy是一样的。
mixins 混入
# 引入js,同名方法优先级低于 methods
new Vue({
mixins: [funUtils]
})
组件注册方式
组件作用域隔离;组件只能有另一个根节点;
全局组件
data 必须是函数式写法,必须有返回值
Vue.component("", {})
局部组件
Vue.component("common", {
components:{
"localComponents":{
// 局部组件,该组件只供common组件使用
}
}
})
通信
父传子通信
通过 Prop 向子组件传递数据:不限制类型
父组件在调用子组件的时候赋值
<div id="commucation">
<p>父组件</p>
// 父传子通信,如果动态传值可以对 param 使用 v-bind 绑定
<child param="君不见黄河之水天上来"></child>
</div>
子组件通过 props 属性获取父组件的传参
Vue.component("child", {
template:
`
<nav>
<span style="background: yellow">子组件</span>
<br>
{{ param }}
</nav>
`,
// props:["param"]
// 属性验证
props:{
param:String
}
})
完整示例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="commucation">
<p>父组件</p>
<child param="君不见黄河之水天上来"></child>
</div>
</body>
<script type="text/javascript">
// 组件之间互不影响,没有任何关联,但是可以通信
// 子组件
Vue.component("child", {
template:
`
<nav>
<span style="background: yellow">子组件</span>
<br>
{{ param }}
</nav>
`,
// props:["param"]
// 属性验证
props:{
param:String
}
})
// 父组件
let vm = new Vue({
el: "#commucation"
})
</script>
</html>
子传父通信
通过事件通知父组件
子组件通过事件通知父组件调用子组件时绑定的事件
childClick(){
console.log("子组件点击调用")
// 使用 this.$emit 通知父组件的中调用子组件标签中的事件,1000 为参数
this.$emit("noticeevent", 1000);
}
父组件在调用子组件的时候绑定事件,并指定父组件中接收参数的函数
# 调用子组件
<div id="commucation">
<p>父组件</p>
<child @noticeevent="getChildParam"></child>
</div>
# 接收参数的函数
// 父组件
let vm = new Vue({
el: "#commucation",
methods:{
// data 为子组件传的参数
getChildParam(data){
console.log("data", data)
}
}
})
完整示例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="commucation">
<p>父组件</p>
<child @noticeevent="getChildParam"></child>
</div>
</body>
<script type="text/javascript">
// 组件之间互不影响,没有任何关联,但是可以通信
// 子组件
Vue.component("child", {
template:
`
<nav>
<span style="background: yellow">子组件</span>
<br>
<button @click="childClick()">子组件click</button>
<br>
</nav>
`,
methods:{
childClick(){
console.log("子组件点击调用")
// 通知父组件的中调用子组件标签中的事件
this.$emit("noticeevent", 1000);
}
}
})
// 父组件
let vm = new Vue({
el: "#commucation",
methods:{
getChildParam(data){
console.log("data", data)
}
}
})
</script>
</html>
refs 通信
1:ref 绑定在标签上, this. r e f s 获 取 原 生 标 签 ; 2 : r e f 绑 定 在 组 件 上 , t h i s . refs 获取原生标签; 2:ref 绑定在组件上, this. refs获取原生标签;2:ref绑定在组件上,this.refs 获取时组件对象;
ref 绑定在标签上
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="commucation">
<input type="text" ref="name"/>
<button type="button" @click="getDom">GET</button>
</div>
</body>
<script type="text/javascript">
// 父组件
let vm = new Vue({
el: "#commucation",
methods:{
getDom(){
// this.$refs 获取所有ref
// this.$refs.name 获取ref值为name的节点
// this.$refs.name.value 获取ref值为name节点的值
console.log("获取的值为:", this.$refs.name.value)
}
}
})
</script>
</html>
ref 绑定在组件上
父传子
父组件通过 ref 绑定调用子组件的调用标签,通过 this.refs.childComponent(childComponent指定的是父组件调用子组件绑定的ref值)获取子组件,通过this.refs.childComponent (childComponent指定的是父组件调用子组件绑定的ref值)获取子组件,通过 this.refs.childComponent(childComponent指定的是父组件调用子组件绑定的ref值)获取子组件,通过this.refs.childComponent.getParent(params) 调用子组件的函数
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="commucation">
<p>父组件</p>
<input type="text" ref="inputVal"/>
<button type="button" @click="transferVal">通过refs传值给子组件</button>
<child ref="childComponent"></child>
</div>
</body>
<script type="text/javascript">
// 组件之间互不影响,没有任何关联,但是可以通信
// 子组件
Vue.component("child", {
template:
`
<nav>
<span style="background: yellow">子组件</span>
<br>
</nav>
`,
methods:{
getParent(data){
console.log("获取父组件的值为:", data)
}
}
})
// 父组件
let vm = new Vue({
el: "#commucation",
methods:{
transferVal(){
console.log("this.$refs.inputVal.value", this.$refs.inputVal.value);
let params = this.$refs.inputVal.value;
// 获取ref绑定的子组件,并调用子组件的函数(可以传参)
// this.$refs.childComponent 获取子组件
// this.$refs.childComponent.getParent(params) 调用子组件的函数
this.$refs.childComponent.getParent(params);
}
}
})
</script>
</html>
bus 通信(简单的非父子通信)
发布订阅模式,通过同一个 vue 实例作为中间件中心
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="commucation">
<p>父组件</p>
<child1></child1>
<child2></child2>
</div>
</body>
<script type="text/javascript">
// 创建一个 vue 实例,作为中央事件总线
let bus = new Vue();
// 子组件 1
Vue.component("child1", {
template:
`
<nav>
<span style="background: yellow">子组件 1</span>
<button @click="transferData()">transfer</button>
</nav>
`,
methods:{
transferData(){
console.log("开始输出数据");
// 通知dataMount事件
bus.$emit("dataMount", "君不见黄河之水天上来")
}
}
})
// 子组件 2
Vue.component("child2", {
template:
`
<nav>
<span style="background: red">子组件 2</span>
<br>
</nav>
`,
mounted() {
// 监听dataMount事件
bus.$on("dataMount", (data)=>{
console.log("the data is ", data);
})
}
})
// 父组件
let vm = new Vue({
el: "#commucation"
})
</script>
</html>
Vuex
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
// 共享状态
},
mutations: {
// 用于修改共享状态
},
actions: {
// ajax 异步请求调用 mutations 中的函数,修改共享状态
},
});
// 其他vue组件通过 "this.$store.state.共享状态属性" 进行访问
动态组件
<!--is绑定的是组件名,组件切换会从重新渲染-->
<component :is=""></component>
<!--keep-alive保留组件状态,避免重新渲染-->
<keep-alive>
<component :is=""></component>
</keep-alive>
slot 插槽
插槽是混合父组件的内容混到子组件中
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="commucation">
<p>父组件</p>
<child>
<!--ul 标签内容属于父组件的内容-->
<ul>
<li>11111111</li>
<li>22222222</li>
<li>33333333</li>
</ul>
</child>
</div>
</body>
<script type="text/javascript">
// 子组件 2
Vue.component("child", {
template:
`
<nav>
<div>子组件</div>
<!--slot插槽:混合父组件的内容混到子组件中-->
<slot></slot>
</nav>
`
})
// 父组件
let vm = new Vue({
el: "#commucation"
})
</script>
</html>
具名插槽
插槽具有名字,可以使用name属性指定使用插槽的位置
父组件使用 slot 属性指定插槽名称
子组件使用 指定slot名称
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="commucation">
<p>父组件</p>
<child>
<!--slot指定名称,将父组件的内容匹配到对应插槽位置上-->
<div slot="slot1">aaaaa</div>
<div slot="slot2">bbbbb</div>
<div slot="slot3">ccccc</div>
</child>
</div>
</body>
<script type="text/javascript">
// 子组件 2
Vue.component("child", {
template:
`
<nav>
<div>子组件</div>
<!--slot插槽:混合父组件的内容混到子组件中, name指定插槽名称-->
<div style="background: red">
<slot name="slot1"></slot>
</div>
<div style="background: yellow">
<slot name="slot2"></slot>
</div>
<div style="background: blue">
<slot name="slot3"></slot>
</div>
</nav>
`
})
// 父组件
let vm = new Vue({
el: "#commucation"
})
</script>
</html>
过滤器
自定义过滤器
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="commucation">
{{name | msgFilter}}
</div>
</body>
<script type="text/javascript">
let vm = new Vue({
el: "#commucation",
data:{
name: "君不见黄河之水天上来"
},
filters:{
msgFilter: function(value){
console.log("value", value)
// 处理数据
return value.split('之')[1];
}
}
})
</script>
</html>
路由
路由容器
<router-view name=""></router-view>
hash 路由
location.hash 切换
window.onhashchange 监听路径的切换
history 路由
// 路径没有 #
const router = new Router({
mode : "history",
})
history.pushState 切换
window.onpopstate 监听路径的切换
嵌套路由
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
// 注册路由模块
Vue.use(Router)
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'home',
alias: "/index", // 别名
component: Home,
children:[
{
path: '/',
name: 'home',
component: Home,
}
]
},
// 重定向
{
path: '/li',
name: 'li',
redirect: "/about"
}
]
})
动态路由配置
{
# 使用 :id 做动态路由配置,: 是做一个占位符
path: '/detail/:id1/:id2/:id3',
name: 'home'
component: Detail
}
# 编程式路由
## 路径跳转
this.$router.push(`/path/{id}`)
## 路由名称跳转
this.$router.push({name:"",params:{}})
# 声明式路由
<router-link>
获取hash值
# 获取当前路由
let hashVal = location.hash
# 获取当前路由信息
this.$route
路由守卫
全局守卫
在 router.js 配置
router.befaoreEach((to, from, next) => {
if(to.path === '/center'){
// 拦截判断
if(usre.isLogin()){
// 有登录信息,可以访问
next();
}else{
// 无登录信息,需要登录
next('/login')
}
}else{
// 允许过去
next();
}
})
Vuex
1:管理共享状态——解决非父子通信
2:数据快照——缓存后端数据,避免重复请求,影响用户体验
3:时光旅行——调式