一、Vue核心知识介绍
1、Vue简介
1)什么是Vue Vue 是一套用于构建用户界面的渐进式框架。
2)jQuery与Vue的区别
- jQuery是基于操作dom的库
- Vue框架是以数据驱动和组件化开发为核心
2、引包、留坑、实例化 、插值表达式{{}}
<body>
<!-- 2、留坑 -->
<div id="app"></div>
<!-- 1、引包 -->
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript"></script>
</body>
3、常用指令
1)什么是指令
在vue中提供一些对于页面 + 数据更为方便的操作,这些操作就叫做指令。
- 在vue中v-xxx就是vue的指令
- 指令就是以数据去驱动DOM行为的,简化DOM操作
2)常用指令
- v-text:不可解析html标签
- v-html:可解析html标签
- v-if:做元素的插入(append)和移除(remove)操作
- v-else-if:与v-if配对使用
- v-else:与v-if配对使用
- v-show:display:none和display:block的切换
- v-for
- 数组 item,index
- 对象 value,key ,index
<body>
<div id="app"></div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
new Vue({
el:'#app',
template:`
<div>
<!--测试v-text-->
<div v-text='mytext'></div>
<hr>
<!--测试v-html-->
<div v-html='myhtml'></div>
<hr>
<!--测试v-if v-else-if v-else-->
<button v-if='checkvif'>测试v-if</button>
<button v-if='num==1'>测试v-if</button>
<button v-else-if='num==2'>测试v-else-if</button>
<button v-else>测试v-else</button>
<hr>
<!--测试v-show-->
<div v-show='checkshow'>我是V-SHOW</div>
<hr>
<!--循环数组-->
<ul>
<li v-for='(item,index) in arrayfor'>
{{ item }}-{{index}}
</li>
</ul>
<hr>
<!--循环对象-->
<ul>
<li v-for='(oj,key) in ojfor'>
{{key}}:{{oj}}
</li>
</ul>
</div>
`,
data:function(){
return {
mytext:'<h1>我这里是v-text</h1>',
myhtml:'<h1>我这里是v-html</h1>',
checkvif:false,
num:6,
checkshow:true,
arrayfor:['篮球','足球','乒乓球'],
ojfor:{play:'篮球',people:'ming',age:'19'}
}
}
})
</script>
</body>
4、单双向数据流及事件绑定
1)vue单向数据流绑定属性值,v-bind:(属性),可简写为:(属性)
例子:<input v-bind:value="name" v-bind:class="name">
- 单向数据绑定,内存改变影响页面改变
- v-bind就是对属性的简单赋值,当内存中值改变,还是会触发重新渲染
2)vue双向数据流,v-model只作用于有value属性的元素
例子:<input v-model="name" v-bind:class="name">
- 双向数据绑定,页面对于input的value改变,能影响内存中name变量
- 内存js改变name的值,会影响页面重新渲染最新值
3)事件绑定,v-on:事件名="表达式||函数名",可简写为@事件名="表达式||函数名"
- 事件名可以是原生也可以是自定义的
<body>
<div id="app"></div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
console.log(this)
new Vue({
el:"#app",
template:`
<div>
单向数据绑定
<input type='text' v-bind:value="name" :class="name">
<br>
双向数据绑定
<input type='text' v-model="name">
</br>
{{name}}
<br>
<button v-on:click="name = '我改变了'">点击我改变name变量</button>
<br>
<button v-on:click="change">点击我改变name变量</button>
</div>
`,
data:function(){
return {
name:'hello'
}
},
methods:{
change:function(){
console.log(this)
this.name='我改变了,是在方法属性里面定义的方法'
},
}
})
</script>
</body>
5、过滤器的使用
- 过滤器就是可以对我们的数据进行添油加醋然后再显示
- 过滤器有全局过滤器和组件内的过滤器
- 全局过滤器Vue.filter('过滤器名',过滤方式fn);
- 组件内的过滤器filters:{ '过滤器名',过滤方式fn }
- {{ msg | 过滤器名}}
- 最终都是在过滤方式fn里面return产出最终你需要的数据
<body>
<div id="app">
我输入的:<input type="text" name="" v-model='instring'></br>
我输出的:{{ instring }}</br>
{{ instring | reversal('翻转输出:')}}
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
console.log(this)
//Vue.filter('reversal',function(val,arg2){
//return arg2+val.split('').reverse().join('')
//})
new Vue({
el:'#app',
data(){
return {
instring:''
}
},
created(){
console.log(this)
},
filters:{
reversal(val,arg2){
//字符串转数组 翻转 数组转字符串
return arg2+val.split('').reverse().join('')
}
}
})
</script>
</body>
6、数据监听watch与计算属性computed
watch监听单个数据,computed监听多个数据
1)当watch监听的是复杂数据类型的时候需要做深度监听(写法如下)
watch:{
msg:{
handler(val){
if(val.text=='love'){
alert(val.text)
}
},
deep:true//开启深度监听
}
}
2)computed监视对象,写在了函数内部,凡是函数内部有this.相关属性,改变都会触发当前函数
<body>
<div id="app">
<div>watch监听数据</div>
<input type="text" name="" v-model='msg.text'>
<div>computed计算属性</div>
(<input type="text" name="" v-model='n1'>+
<input type="text" name="" v-model='n2'>)*
<input type="text" name="" v-model='n3'>={{result}}
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
new Vue({
el:'#app',
data(){
return {
msg:{text:''},
n1:'',
n2:'',
n3:'1'
}
},
computed:{
result(){
return (Number(this.n1)+Number(this.n2))*Number(this.n3)
}
},
watch:{
// msg(newval,oldval){
// if(newval.text=='love'){
// alert(newval.text)
// }
// }
msg:{
handler(newval,oldval){
if(newval.text=='love'){
alert(newval.text)
}
},
deep:true
}
}
})
</script>
</body>
二、组件化开发知识介绍
1、组件化开发
-
创建组件的两种方式
局部声明
var Header = { template:'模板',data:'函数',methods:'功能',components:子组件们 }全局声明注册
Vue.component('组件名',组件对象); -
组件类型
- 通用组件(例如表单、弹窗、布局类等)
- 业务组件(抽奖、机器分类)
- 页面组件(单页面开发程序的每个页面的都是一个组件、只完成功能、不复用)
-
组件开发三步曲:声明、注册、使用
- 组件化开发代码示例
<body>
<div id="app"></div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
// var MyHeader=Vue.extend({
// template:`<div>我是身体1</div>`
// })
//1、局部声明组件(语法糖)
var MyHeader = {
template:`<div>我是头部</div>`
}
var MyBody = {
template:`<div>我是身体</div>`
}
//全局声明组件(不需要注册)
Vue.component('MyFooter',{
template:`<div>我是尾部</div>`
})
new Vue({
el:'#app',
//2、局部注册组件
components:{
MyHeader,
MyBody
},
//使用组件
template:`
<div>
<!-- 使用组件 -->
<my-header></my-header>
<my-body></my-body>
<my-footer></my-footer>
</div>
`
});
</script>
</body>
2、slot插槽和ref、$parent
-
slot插槽
slot就是子组件里给DOM留下的坑位
<子组件>DOM</子组件>
slot是动态的DOM
-
ref获取子组件实例
识别:在子组件或元素上使用属性ref="xxxx"
获取:this.$refs.xxxx 获取元素
$el 是拿其DOM
-
$parent获取父组件实例
<body>
<div id="app"></div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
var Child={
template:`
<div>我是子组件</div>
`,
data(){
return {
msg:'hello'
}
},
created(){
console.log(this.$parent)
}
}
var Parent={
template:`
<div>
我是父组件
<slot name='hello'></slot>
<child ref='childs'></child>
</div>
`,
components:{
Child
},
data(){
return {
parents:'我是父组件'
}
},
mounted(){
// console.log(this.$refs.childs)
}
}
new Vue({
el:'#app',
components:{
Parent
},
template:`
<div>
<parent>
<div>我是插槽内容</div>
<div slot='hello'>我是插槽内容2</div>
</parent>
</div>
`
})
</script>
</body>
3、父子组件的通信
-
父传子
- 父用子的时候通过属性传递
- 子要声明props:['属性名'] 来接收
- 收到就是自己的了,随便你用
- 在template中 直接用
- 在js中 this.属性名 用
-
子传父
-
子组件里通过$emit('自定义事件名',变量1,变量2)触发
-
父组件@自定义事件名=‘事件名’监听
-
子组件方法里 this.$emit('sendfather',val1,val2)触发自定义事件 父组件里 <child @sendfather='mymethods'></child>
-
<body>
<div id="app"></div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
//子组件定义好了props直接用
var Child={
template:`<div>我是子组件{{sendchild}}</div>`,
props:['sendchild']
}
//父组件通过属性sendchild传递了数据给子组件
var Parent={
template:`
<div>我是父组件{{ msg }}
<child sendchild='父亲给你的' @baba='reserve'></child>
</div>
`,
components:{
Child
},
}
new Vue({
el:'#app',
components:{
Parent
},
template:`<div><parent></parent></div>`
})
</script>
</body>
<body>
<div id="app"></div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
//子组件定义好了props直接用
var Child={
template:`
<div>
<button @click='sendparent'>我要反馈东西给父亲</button>
</div>
`,
methods:{
sendparent(){
this.$emit('baba','这是儿子组件给你的')
}
}
}
//父组件通过属性sendchild传递了数据给子组件
var Parent={
template:`
<div>
我是父组件{{ msg }}
<child @baba='reserve'></child>
</div>
`,
components:{
Child
},
data(){
return {
msg:''
}
},
methods:{
reserve(val){
this.msg = val;
}
}
}
new Vue({
el:'#app',
components:{
Parent
},
template:`
<div>
<parent></parent>
</div>
`
})
</script>
</body>
4、非父子组件之间的通信
-
创建一个空实例(bus中央事件总线也可以叫中间组件)
-
利用
on的触发和监听事件实现非父子组件的通信
Vue.prototype.$bus=new Vue()//在vue上面挂载一个$bus作为中央处理组件 this.$bus.$emit('自定义事件名','传递的数据')//触发自定义事件传递数据 this.$bus.$on('自定义事件名',fn)//监听自定义事件获取数据
解决的方案还有vuex、provide/inject是解决同根往下派发、本地存储也可以进行非父子组件之间的通信
3、vue的生命周期
-
需要频繁的创建和销毁组件
-
比如页面中部分内容显示与隐藏,但是用的是v-if
-
-
组件缓存
-
内置组件中
-
被其包裹的组件,在v-if=false的时候,不会销毁,而是停用
-
v-if="true" 不会创建,而是激活
-
避免频繁创建组件对象的性能损耗
-
组件的激活和停用
-
activated 和 deactivated
-
-
-
成对比较
-
created 和 beforeCreate
-
A 可以操作数据 B 数据没有初始化
-
-
mounted 和 beforeMount
-
A 可以操作DOM B 还未生成DOM
-
-
updated 和 beforeUpdate
-
A 可以获取最终数据 B 可以二次修改
-
-
destroyed 和 beforeDestroy
性能调优:频繁销毁创建的组件使用内置组件****包裹
-
三、Vue核心插件之路由模块
1、路由的跳转原理(哈希模式)
-
单页应用的路由模式有两种
1、哈希模式(利用
hashchange事件监听url的hash改变)2、history模式(使用此模式需要后台配合把接口都打到我们打包后的index.html上)
-
哈希模式原理代码示例
<body>
<a href="#/login">登录</a>
<a href="#/register">注册</a>
<div id="app"></div>
<script type="text/javascript">
var appdiv=document.getElementById('app')
window.addEventListener('hashchange', function(e) {
console.log(location.hash)
switch(location.hash){
case '#/login':
appdiv.innerHTML='我是登录页面';
break;
case '#/register':
appdiv.innerHTML='我是注册页面';
break;
}
})
</script>
</body>
核心是锚点值的改变,我们监听到锚点值改变了就去局部改变页面数据,不做跳转。跟传统开发模式(url改变后立刻发起请求,响应整个页面,渲染整个页面)比,路由的跳转用户体验更好
2、安装和使用路由
-
vue-router是vue的核心插件,vue-router是以插件的形式引入到我们的vue项目中来的
1、下载
npm i vue-router2、安装插件
Vue.use(VueRouter);3、创建路由对象
var router = new VueRouter();4、配置路由规则
router.addRoutes([{path:'锚点值',component:要(填坑)显示的组件}]);5、将配置好的路由对象交给Vue
router:router6、留坑(使用组件)
<router-view></router-view> -
使用路由代码示例
<body>
<div id="app"></div>
<script type="text/javascript" src="vue.js"></script>
<!-- 1、引入路由插件 -->
<script type="text/javascript" src="vue-router.js"></script>
<script type="text/javascript">
var Login={
template:`<div>我是登录页面</div>`,
}
//2、安装路由插件
Vue.use(VueRouter);
//3、创建路由对象
var router= new VueRouter({
//4、配置路由规则
routes:[
{path:'/login',name:'login',component:Login}
]
})
new Vue({
el:'#app',
//5、将配置好的路由对象交给Vue
router:router,
template:`
<div>
<p>请在链接上加上login测试路由功能</p>
<!-- 6、留坑(使用组件) -->
<router-view></router-view>
</div>
`
})
</script>
</body>
3、路由跳转
-
路由的跳转方式有:
1、通过标签
<router-link to='/login'></router-link>2、通过js控制跳转
this.$router.push({path:'/login'}) -
push跳转与replace跳转的区别
1、this.$router.push() 跳转到指定的url,会向history插入新记录
2、this.$router.replace() 跳转到指定的url,不会向history插入新记录,点击返回,会跳转到上上一个页面。上一个记录是不存在的
3、this.$router.go(-1) 常用来做返回,读取history里面的记录后退一个
-
vue-router中的对象:
1、$route 路由信息对象,只读对象
2、$router 路由操作对象,只写对象
-
路由跳转代码示例
<body>
<div id="app"></div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript" src="vue-router.js"></script>
<script type="text/javascript">
var Login={
template:`<div>我是登录页面</div>`,
}
var Register={
template:`<div>我是注册页面</div>`,
}
var Buy={
template:`<div>我要买东西</div>`,
}
Vue.use(VueRouter);
var router= new VueRouter({
routes:[
{path:'/login',name:'login',component:Login},
{path:'/register',name:'register',component:Register},
{path:'/buy',name:'buy',component:Buy}
]
})
new Vue({
el:'#app',
router,
template:`
<div>
<router-link to='/login'>去登录</router-link>
|
<router-link to='/register'>去注册</router-link>
<div>
<button @click='goregister'>我要去买东西</button>
<button @click='back'>返回上一页</button>
</div>
<router-view></router-view>
</div>
`,
methods:{
goregister(){
// push跟replace是达到同样效果,但是replace是不会向history插入记录
// this.$router.push({path:'/register'})
this.$router.replace({path:'/buy'});
},
back(){
this.$router.go(-1);
}
}
})
</script>
</body>
4、路由传参和取参
-
查询参数
配置(传参) :to="{name:'login',query:{id:loginid}}"
获取(取参) this.$route.query.id
-
路由参数
配置(传参) :to="{name:'register',params:{id:registerid} }"
配置路由的规则 { name:'detail',path:'/detail/:id'}
获取 this.$route.params.id
-
总结:
:to传参的属性里 params是和name配对的 query和name或path都可以
使用路由参数必须要配置路由规则里面配置好参数名,否则刷新页面参数会丢失
-
路由传参与取参代码示例
<body>
<div id="app"></div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript" src="vue-router.js"></script>
<script type="text/javascript">
var Login={
template:`
<div>我是登录页面
<span>这是我获取到的参数:{{ msg }}</span>
</div>
`,
data(){
return {
msg:''
}
},
created(){
//获取查询参数
this.msg=this.$route.query.id
}
}
var Register={
template:`
<div>我是注册页面
<1-- <span>这是我获取到的路由参数:{{ registerfoo }}</span> -->
<span>这是我获取到的路由参数:{{ foo }}</span>
</div>
`,
//获取路由参数有两种方式:钩子函数与props属性
//props:['foo']
//data(){
// return {
// registerfoo:''
// }
//},
//created(){
// //获取路由参数
// this.registerfoo=this.$route.params.foo
//}
}
Vue.use(VueRouter);
var router= new VueRouter({
routes:[
{path:'/login',name:'login',component:Login},
//{path:'/register/:foo',name:'register', component:Register}
{path:'/register/:foo',name:'register',props:true, component:Register}
]
})
new Vue({
el:'#app',
router,
template:`
<div>
<router-link :to="{name:'login',query:{id:'123'}}">去登录</router-link>
|
<router-link :to="{name:'register',params:{foo:'bar'}}">去注册</router-link>
<button @click='jslink'>js跳转去登录</button>
<!-- :key解决js跳转路由传参和标签传参路由相同而参数不同时页面不做刷新的问题 -->
<router-view :key="$route.fullPath"></router-view>
</div>
`,
methods:{
//js跳转传参
jslink(){
this.$router.push({name:'login',query:{id:'456'}})
}
}
})
</script>
</body>
5、嵌套路由
-
1、router-view的细分
router-view第一层中,包含一个router-view
-
2、每一个坑挖好了,要对应单独的组件
-
3、嵌套路由代码示例
<body>
<div id="app"></div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript" src="vue-router.js"></script>
<script type="text/javascript">
var Nav={
template:`
<div>
<router-view></router-view>
<router-link :to="{name:'nav.index'}">首页</router-link>
|
<router-link :to="{name:'nav.pensonal'}">个人中心</router-link>
|
<router-link :to="{name:'nav.message'}">资讯</router-link>
|
<router-link :to="{name:'nav.mine'}">我的</router-link>
</div>
`,
}
var Index={
template:`<div>首页</div>`,
}
var Pensonal={
template:`<div>个人中心</div>`,
}
var Message={
template:`<div>资讯</div>`,
}
var Mine={
template:`<div>我的</div>`,
}
Vue.use(VueRouter);
var router= new VueRouter({
routes:[{
path:'/nav',
name:'nav',
component:Nav,
//嵌套路由增加这个属性
children:[
//重定向到首页
{path:'',redirect:'/nav/index'},
//配置我们的嵌套路由
{path:'index',name:'nav.index',component:Index},
{path:'pensonal',name:'nav.pensonal',component:Pensonal},
{path:'message',name:'nav.message',component:Message},
{path:'mine',name:'nav.mine',component:Mine}
]
}]
})
new Vue({
el:'#app',
router,
template:`
<div>
<router-view></router-view>
</div>
`
})
</script>
</body>
6、路由守卫
-
路由守卫相关钩子函数
const router = new VueRouter({ ... })
//前置的钩子函数 最后要执行next()才会跳转
router.beforeEach((to, from, next) => {
// ...
})
//后置的钩子函数 已经跳转了不需要next()
router.afterEach((to, from) => {
// ...
})
-
路由守卫代码示例
<body>
<div id="app"></div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript" src="vue-router.js"></script>
<script type="text/javascript">
var Nav={
template:`
<div>
<router-view></router-view>
<router-link :to="{name:'nav.index'}">首页</router-link>
|
<router-link :to="{name:'nav.pensonal'}">个人中心</router-link>
|
<router-link :to="{name:'nav.message'}">资讯</router-link>
|
<router-link :to="{name:'nav.mine'}">我的</router-link>
</div>
`,
}
var Index={
template:`<div>首页</div>`,
}
var Pensonal={
template:`<div>个人中心</div>`,
}
var Message={
template:`<div>资讯</div>`,
}
var Mine={
template:`<div>我的</div>`,
}
Vue.use(VueRouter);
var router= new VueRouter({
routes:[{
path:'/nav',
name:'nav',
component:Nav,
children:[
{path:'',redirect:'/nav/index'},
{path:'index',name:'nav.index',component:Index},
{path:'pensonal',name:'nav.pensonal',component:Pensonal},
{path:'message',name:'nav.message',component:Message},
{path:'mine',name:'nav.mine',component:Mine},
]
}]
})
new Vue({
el:'#app',
router,
template:`
<div>
<router-view></router-view>
</div>
`,
mounted(){
//利用路由守卫做当跳转首页时可直接跳转,跳转其他页面要等待两秒才可以跳转
router.beforeEach((to,from,next)=>{
console.log(to)
if(to.path=='/nav/index'){
next()
}else{
setTimeout(function(){
next();
},2000)
}
})
}
})
</script>
</body>