Vue进阶篇

前引

  今天是 2018 年 12 月 30,虽不是 2018 年的最后一天,但是却是自己在 2018 年写的最后一篇博客了,昨天下班在地铁上闲来无事,翻起了关注的一些公众号发的技术博文,里面就提到写博客的重要性,其实这样的内容看了 N 多了,但是,里面有一句感觉说的很对,现在的博客变了味了,因为我们可以 Ctrl+c、Ctrl+v,短短几秒钟就是一遍几千字的博文,真正自己写出的博文需要花费很长的时间。说心里话,自己的博客中也有,大概有三分之一吧,突然莫名的恐慌,因为很可能就是这三分之一的博客,就会掩盖自己花费精力完成的其他的博客,被别人冠上这么一个标签,这人也是一个充数的、装大半蒜的家伙。其实内心已经一万个草泥马了,因为我们都是人,说话说的好,一个人一直做好事,但是突然有一天做了一件坏事,大家就定义这个人是坏人,好人难做啊,同样的,写博客亦如此。

  不感慨了,看到的小伙伴们支持一下,当然欢迎转载,欢迎 Ctrl+c,但是有一个请求,在文章的最上方请注明文章来源,非常感谢。

  接下来,说今天的正事,本篇博客的正事,Vue 的进阶篇,进阶,谈不上,也算是一点稍微不那么基础的基础吧,更基础的欢迎浏览本人的另一篇博客Vue 基础篇

 

老习惯,开始正文之前,先来了解一些必知必会的小知识点

前言

  1,组件和插件的区别(组件是一个项目的必须组成部分,而插件是不必须的,动态的,即插即用)

  2,在一个项目中,一个文件以. 开头表示电脑系统的隐藏文件。

  3,在前端中,一个项目中的 index 文件或 main 文件,默认为一个项目的入口

  备注:在 vue-cli 项目中会有一个包含很多包的文件,这个文件的文件名就是 node_modules,还有一个.gitignore 的文件,这个隐藏文件的意思就是 git 忽视的一个文件,打开这个文件,里面的有这些内容:

.DS_Store
node_modules
/dist

  在这个文件中,我们可以配置当前项目一些忽略的文件,支持部分正则匹配。比如,node_modules 项,如果项目上传 git,或者 GitHub 时,会自动忽略掉这个文件,所以我们上传到 GitHub 上的项目中是不包含这个 node_modules 文件的,这也是 GitHub 的一个局限性,大的文件无法上传,导致我们从 GitHub 上下载的一些开源的项目,并不能直接使用,对于 vue 的项目,还需要使用一个命令:npm install  将包含很多包的这个文件下载下来。

  因此,我们从 GitHub 上下载下来的 vue 的开源代码,第一步就是运行一个命令:npm install (一般在当前目录下)   

  GitHub 中,每个开源文件都有一个文件 READMI.md(markdown 文件),这个文件中,会告诉我们怎么使用这个项目。

  赠送的小技巧:另外的我们在一个项目名中,看到带有 awesome 的,表示一个生态系统,里面在这个基础上封装了很多插件和模块。

vue-cli 开始

  在 vue 中,一个.vue 文件就是一个 vue 的组件。

一个标准的可重用的 vue 组件的格式:

<!--一个组件包含 html、css、js-->

<template>
<!--组件的结构-->

</template>

<script>
// 处理业务逻辑
  export default {
name: "Vheader",

  }
</script>

<style>
/页面的样式/

</style>

  备注

  1,在 template 模板中,必须有一个包裹的标签。   需要注意的是:template 不是一个标签,是 vue 中的一个模板

  2,在 vue 中,一个组件的命名规范是:首字母必须大写,比如:所有的组件以“V”开头。一个组件中的 data(数据属性)必须是函数,这个函数必须 return 一个对象。

  3,在一个项目中的 MP3 文件,由于 webpack 的打包编译,是无法直接引入到 src 中,所以导入 MP3 文件时,必须当做模块来引入

import song1 from './assets/ 薛之谦 - 一半 [mqms2].mp3'
<audio src="song1" autoplay controls></audio>

  总之,所有的静态资源都可以作为模块导入 。

 

组件的引入

  组件的引入很简单 ,分三步:

  1,导入组件       import  Vheader  from  './components/Vheader.vue'

  2,挂载组件       在 export  default 中  定义一个 key 为 components,值为一个对象,这个对象中放着导入键值对;键为变量名,值为组件名,在 es6 中,键值相同时,可以缩写为一个单一的值。

  比如:components:{Vheader}

  3,在 template 模板中使用组件:     <Vheader> </Vheader>

备注:在父组件中定义的样式类,默认为全局的样式类,所以如果要保证自身元素的样式,在子组件的 style 标签中加入:scoped 即可     <style  scoped><style>

 

父子传值

父子组件的传值:

父组件向子组件传值

  1,绑定自定义的属性   :  在父组件中对应的子组件的模板上绑定属性。

    比如:<Vcontent  :menu=“menus”><Vcontent>     #menu 为定义的属性名   menus 为数据属性

  2,在子组件中接收这个自定义的属性,并且属性必须要验证   ,接收的属性放在 props 中

    比如:props:{menu:Array}         备注:接收的变量名必须与自定义的变量名保持一致

  3,这时子组件中的数据值就是这个对应的 menu 变量,我们也可以在数据属性中重新赋值

    比如:data(){return {  menus:this.menu }  }    #这时我们在子组件用的值就是 menus 了

  备注:这里的 this 是指当前的子组件的 Vue 对象,Vue 创建组件时:Vue.component()

子组件向父组件传值

  1,在子组件中定义一个事件: 比如:在 Vheader 中定义一个点击事件。     

<template>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">div </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="header"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span><span style="color: rgba(0, 0, 0, 1)">

    //  定义一个点击事件   addOne   
    </span><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">button </span><span style="color: rgba(255, 0, 0, 1)">@click</span><span style="color: rgba(0, 0, 255, 1)">="addOne"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>添加一个菜单<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">button</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">div</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</template>

<script>
export
default {
name:
"Vheader",
data(){
return {

        }
    },
    methods:{
         </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">//</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 128, 0, 1)">  事件触发自定义的事件</span>

addOne(){
this.$emit('addMenu','酸菜鱼'); #this.$emit(“自定义事件名”,“往父组件传的值”)
}
}
}
</script>

<style scoped>

</style>

  2,触发自定义的事件,this.$emit("自定义的事件名","要向父组件传的值")    #备注:固定写法,而且自定义的事件名必须与父组件中自定义的事件名一致

  3,在父组件中对应的子组件模板中,定义好这个自定义事件,比如:<Vheader @addMenu="addHand"></Vheader>

    并在对应的事件中,接收传的值,并做相应处理。

   methods:{addHand(value){this.menus.push(value);   #接收传的值,并将值添加到父组件的 menus 数组中
          }
    }    

 

vue 的优势和用途

  

vue 主做单页面应用

  比如:饿了么、掘金、网易云音乐、豆瓣、知乎等等

在 vue 中,可以给每一个单页面(组件)配置一个路由,这个是由 vue-router 来控制的 

vue-router

首先,要在我们的项目中下载安装这个 vue-router   

npm install vue-router

 

如果在一个模块化工程中使用它,必须要通过 Vue.use() 明确地安装路由功能:

在项目的入口  main.js 中

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

 

接着就可以在这个 main.js 中配置组件

1. 定义 (路由) 组件。

// 比如:
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
// 也可以从其他文件 import 进来
import Vhome from './components/Vhome.vue' import Vuser from './components/Vuser.vue'
2. 定义路由
2. 定义路由
每个路由应该映射一个组件。 其中"component" 可以是通过 Vue.extend() 创建的组件构造器,或者,只是一个组件配置对象。
每个路由应该映射一个组件。 其中"component" 可以是通过 Vue.extend() 创建的组件构造器,或者,只是一个组件配置对象。

const routes = [{ path: '/foo', component: Foo},
  {path: '/bar', component: Bar}
]

3. 创建 router 实例,然后传 `routes` 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({routes // ( 缩写) 相当于 routes: routes
}

4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({router}).$mount('#app')
现在,应用可以启动了!

  Tips: 通过注入路由器,我们可以在任何组件内通过 this.$router 访问路由器,也可以通过 this.$route 访问当前路由:

console.log(this.$router)   #打印 $router 的结果:

    []
    app:Vue {_uid: 0, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
    apps:[Vue]
    beforeHooks:[]
    fallback:false
    history:HashHistory {router: VueRouter, base: "", current: {…}, pending: null, ready: true, …}
    matcher:{match: ƒ, addRoutes: ƒ}
    mode:"hash"
    options:{routes: Array(2)}
    resolveHooks:[]
    currentRoute:(...)
    __proto__:Object

点击打开 __proto__(父级中声明的方法,在子级中都可以使用):

    addRoutes:ƒ addRoutes(routes)
    afterEach:ƒ afterEach(fn)
    back:ƒ back()
    beforeEach:ƒ beforeEach(fn)
    beforeResolve:ƒ beforeResolve(fn)
    forward:ƒ forward()
    getMatchedComponents:ƒ getMatchedComponents(to)
    go:ƒ go(n)
    init:ƒ init(app /* Vue component instance */)
    match:ƒ match( raw, current, redirectedFrom )
    onError:ƒ onError(errorCb)
    onReady:ƒ onReady(cb, errorCb)
    push:ƒ push(location, onComplete, onAbort)
    replace:ƒ replace(location, onComplete, onAbort)
    resolve:ƒ resolve( to, current, append )
    constructor:ƒ VueRouter(options)
    currentRoute:(...)
    get currentRoute:ƒ ()
    __proto__:Object</span></pre>

 

console.log(this.$route)     打印 $route 的结果:


  1. fullPath:"/marked"
  2. hash:""
  3. matched:[{…}]
  4. meta:{}
  5. name:"marked"
  6. params:
    1. __proto__:Object
  7. path:"/marked"
  8. query:{}
  9. __proto__:
    1. constructor:ƒ Object()
    2. hasOwnProperty:ƒ hasOwnProperty()
    3. isPrototypeOf:ƒ isPrototypeOf()
    4. propertyIsEnumerable:ƒ propertyIsEnumerable()
    5. toLocaleString:ƒ toLocaleString()
    6. toString:ƒ toString()
    7. valueOf:ƒ valueOf()
 

 

备注:$router 中,push 方法常用,在 $route 中,path(获取当前访问的路径)和 fullpath(获取当前访问的全路径)方法常用

 

配置好了路由,接下来就该在 HTML 中使用了

<div id="app">
  <h1>Hello App!</h1>
  <p>
    <!-- 使用 router-link 组件来导航. -->
    <!-- 通过传入 `to` 属性指定链接. -->
    <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
    <router-link to="/foo">Go to Foo</router-link>
    <router-link to="/bar">Go to Bar</router-link>
  </p>
  <!-- 路由出口 -->
  <!-- 路由匹配到的组件将渲染在这里 -->
  <router-view></router-view>
</div>

 

备注:路由出口 --> 路由匹配到的组件将渲染在这里 --> <router-view></router-view>  这是路由的出口

使用 router-link 组件来导航. -->通过传入 `to` 属性指定链接. --><router-link> 默认会被渲染成一个 `<a>` 标签

注意:router-link 和 router-view 也可以放置在不同的子组件中

  <router-view></router-view>    可以简写成   <router-view/>

动态路由匹配:

  一个“路径参数”使用冒号 : 标记。当匹配到一个路由时,参数值会被设置到 this.$route.params,可以在每个组件内使用。于是,我们可以更新 User 的模板,输出当前用户的 ID:

const User = {
  template: '<div>User {{$route.params.id}}</div>'
}

 

你可以在一个路由中设置多段“路径参数”,对应的值都会设置到 $route.params 中。例如:

模式匹配路径$route.params
/user/:username /user/evan { username: 'evan' }
/user/:username/post/:post_id /user/evan/post/123 { username: 'evan', post_id: 123 }

除了 $route.params 外,$route 对象还提供了其它有用的信息,例如,$route.query (如果 URL 中有查询参数)、$route.hash

编程式的导航

除了使用 <router-link> 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。

router.push(location, onComplete?, onAbort?)

注意:在 Vue 实例内部,你可以通过 $router 访问路由实例。因此你可以调用 this.$router.push

想要导航到不同的 URL,则使用 router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。

  当你点击 <router-link> 时,这个方法会在内部调用,所以说,点击 <router-link :to="..."> 等同于调用 router.push(...)。所以通过这个方法我们可以实现重定向的效果,

比如:登录后跳转到首页,可以把首页的路径 push 到 $router 中即可

声明式编程式
<router-link :to="..."> router.push(...)

该方法的参数可以是一个字符串路径,或者一个描述地址的对象。例如:

// 字符串
router.push('home')

// 对象
router.push({path: 'home'})

// 命名的路由
router.push({name: 'user', params: { userId: 123}})

// 带查询参数,变成 /register?plan=private
router.push({path: 'register', query: { plan: 'private'}})


  在使用动态路由或者编程式的路由时,会有这样一个问题,路由切换后,页面不切换,解决方法:
使用watch监听路由的变化,并做数据的覆盖处理

<template>
    //  两种方式触发切换
  <!-- 方式一:通过点击事件的切换 -->
<div v-for="(item,index) in theshow.recommend_courses" @click="toaimcourse(item)"><a href="javascript:vild(0);">{{item.title}}</a></div> <!--方式二:通过动态路由的切换--> <router-link v-for="(item,index) in theshow.recommend_courses" :to="{name:'coursedetail', params: { id:item.id}}">{{item.title}}</router-link>

</template>

<script>
export
default {
name:
"vcoursedetail",
data(){
return {
showdetail:
this.$store.state.allCourseDetail,
theshow:
'',
currcourse:
'',
courseall:
this.$store.state.allCourse,
descurl:
'',
charperurl:
''
}
},
created(){
this.courseshowdetail(this.$route.params.id);
this.getcurrentcourse(this.$route.params.id);
},
methods:{
courseshowdetail(nid){

            </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">for</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> (</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> i</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">0</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;i</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">&lt;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.showdetail.length;i</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">++</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">){
                </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">if</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> (</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.showdetail[i].course.id </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">===</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> nid){
                    </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.theshow </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.showdetail[i];
                    </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">return</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.showdetail[i]
                }
            }
        },
             getcurrentcourse(nid){

            </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">for</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> (</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">var</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> i</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">0</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;i</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">&lt;</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.courseall.length;i</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">++</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">){
                </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">if</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> (</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.courseall[i].id </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">===</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> nid){
                    </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.currcourse </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.courseall[i].title;
                    </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.descurl </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/course/coursedetail/</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">+</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">nid;
                    </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.charperurl </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">=</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/course/coursedetail/</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">+</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">nid</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">+</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">/charper</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;
                    console.log(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.descurl,</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">文章摘要的url</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">);
                    </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">return</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.courseall[i]
                }
            }
        },
        toaimcourse(item){
            </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.$router.push({ name: </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">coursedetail</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">, params: { id:item.id }})
        }
    },
    computed:{

    },
    watch:{
        </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">$route</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">"</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">(to,from){
              </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.courseshowdetail(to.params.id);
          </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">this</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">.getcurrentcourse(to.params.id);
        }
    }
}

</script>

 我们也可以做一个全局的路由操作,比如:在每个组件加载或者路由切换时,判断有没有登录

详情参考:https://router.vuejs.org/zh/guide/advanced/navigation-guards.html

完整的导航解析流程

  1. 导航被触发。
  2. 在失活的组件里调用离开守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  5. 在路由配置里调用 beforeEnter
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter
  8. 调用全局的 beforeResolve 守卫 (2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。

拦截过滤认证

单个组件:

  可以在 mounted 方法中做拦截,通过判断全局变量中的 token 值,来判断有无登录。

 

多个组件:可以在全局做拦截

# 在 main.js 中配置

router.beforeEach(function (to,from,next) {
// meta 用于设置一个标识 所以必须在需要验证是否登录的组件中加一个 meta 参数 meta:{requireAuth:true}
if (to.meta.requireAuth){
// 表示此时路径是要判断是否登录的
if (store.state.token){
next()
}else{
// query 用于给这个重定向路由设置一个参数 用于在登录成功后重定向的路径
// 设置此参数后需要在登录成功后做一个判断 this.$route.query.backUrl 获取设置的参数
// 有值,表示是需要跳转回的,然后通过重定向将取的值,定位即可
next({path:'/login',query:{backUrl:to.fullPath}})
}
}else{
next()
}
});

  

bootstrap 的使用

在项目中,使用 bootstrap 时,先在 package.json 中查看开发环境依赖:

  "dependencies": {
    "bootstrap": "^3.3.7",
    "marked": "^0.4.0",
    "vue": "^2.5.16",
    "vue-router": "^3.0.1"
  },

  如果没有,先在当前项目中    npm install xxx

  配置好依赖后,再在需要的地方导入:   导入时,对于 node_modules 文件下的文件,直接导入即可。比如:import 'bootstrap/dist/css/bootstrap.min.css'     在 vue-cli 中,已经配置了路径,所以直接导入即可。

  备注:使用 vue-router 时,路由的切换会在路径前默认加一个 #/,显得 url 很不好看,所以,可以在实例 router 对象时加一个 mode:"history"

const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

 

在使用 a 标签时,会有一个默认的跳转事件,在 vue 中,我们可以在相应的事件后加一个.native 用来阻止原生的默认事件

  @click.native = "xxxx"

参考 Vue 提供的生命周期图示

下图展示了实例的生命周期。你不需要立马弄明白所有的东西,不过随着你的不断学习和使用,它的参考价值会越来越高。

Vue 实例生命周期

  在 vue 的实例的生命周期中,vue 为我们提供了八个方法:

  beforeCreate(在创建之前)、created(创建时的初始化操作,创键的是虚拟 DOM)、beforeMount、mounted(挂载,将虚拟 DOM 转化为真实 DOM)、beforeUpdate、updated、beforeDestroy、destroyed(销毁)

  我们常用的是 created 和 mounted 这两个方法,其中created 方法适用于页面的初始化操作,mounted 适用于发送 ajax 请求数据的操作。

比如:切换路由,页面样式在在此刷新时会出错,可以使用 created 方法进行一些初始化操作

created(){
            for (var i=0;i<this.routes.length;i++){if (this.routes[i].src === this.$route.path){
                    this.current=i;
                    return;
                }
        }
    },</span></pre>

vue-cli 中 2x 版本和 3x 版本修改端口的方法:

在 2x 版本中:

 

 在 3x 版本中:

 

 在 3x 版本中,vue-cli 不推荐我们直接在模块中修改配置

推荐这样:在当前项目的目录下直接创建一个 js 文件   ,文件名必须是    vue.config.js  的形式

在这个 js 文件中写入:

module.exports = {
devServer: { open: process.platform
=== 'darwin', host: '0.0.0.0', port: 8088 , https: false, hotOnly: false, proxy: null, // 设置代理 before: app => {}} }

 修改完成后重启项目即可。

使用 vue-cli 打包文件

生产环境中,我们都会讲项目中的文件打包压缩再上线,vue-cli 中提供了一种快捷的打包方式。

在我们项目的根目录下运行   npm  run  build     就会将项目打包,打包后会在项目中多处一个文件夹 dist,打开这个 dist 文件夹

备注:在项目中替换文件时,最好是先将原文件删除,在拖进去,不要直接替换,放置文件合并

在打包时,一定要配置压缩文件中的路径参数。比如:前缀加 /static/

vue 中的全家桶:vue、vue-router、vuex 构成了 vue 的全家桶,vue 是 MVVM 的架构,vuex--->M     vue--->V     vue-router--->VM

vue 全家桶之 vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式

补充:在 vue 中专门用来发送 ajax 请求的是 axios,详细用法参考:https://www.kancloud.cn/yunye/axios/234845

我们可以在全局的 main.js 或者 store.js 中定义一个 axios    ,将这个 axios 挂到 vue 的实例对象中,这样,在 vue 的子对象中都可以通过 this.$axios 调用到 axios 对象。使用 axios时,可以通过返回的参数response.data 取得返回的数据

import axios from 'axios'
import Vue from 'vue'

Vue.prototype.axios = axios

特别注意:使用 jQuery 的 $.ajax 发送 post 请求发送数据时,内部会自动转化为 json 字符串的形式发送到后端,而使用 vue 中的 axios 时,则不行,axios   post 提交数据时,发送的是普通的值,所有在使用 axios 发送数据时,如果后端需要 json 形式的字符串,则需要借助一个模块  qs (npm install qs) 转化或者,JSON.stringfity  

  还有一个值得注意的地方,在 vue 的中,我们可以通过 this 拿到 vue 的实例对象,但是在axios 中由于作用域的原因则不行,console.log(this) 得到的是一个 undefined,所以我们要在 axios 的外面声明一个变量接收这个 this   var  _this = this


vue 中的 mutation:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。

 使用 vue-cli 时,会在 src 文件夹下默认创建 views、components 的两个文件夹,views 中存放每一个 vue-router(路由)对应的视图,components 中存放父子嵌套的组件。

获取 v-html 指令对应的文本值

  使用 v-html 指令时,如果我们要获取渲染的文本内容,可以给当前标签绑定一个属性 ref="变量名", 然后在 vue 的实例中可以通过 this.$refs. 变量名取得这个标签,在通过 DOM 方法.innerText 取得内容,this.$refs 是一个对象

<div id="show" v-html="currentmsg" ref="mark">

// 这个 div 的文本内容为:
var content = this.$refs.mark.innerText;

备注:不要滥用 ref,对性能有损耗,多个标签时,可以使用 js 方法或者 jQuery 方法获取文本值   $("show").text()

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

备注:mutation 是同步的,action 是异步的,   action 是用来提交的

用法:

mutation 的用法:接收一个 state 参数作为第一个参数,有其他参数可以直接跟在后面,在 mutation 的方法中可以直接操作 state 中的数据,有多个参数时,最好可以将其余的参数作为一个对象,作为方法的第二个参数传值。

 在 vue 的视图中可以直接 this.$store.commit("方法名"),唤醒这个方法的执行

 

action 的用法:接收一个 context 参数作为第一个参数,同样的,后可以跟其他参数,多个参数时,合并为一个 object 对象。通过 context.commit("mutation 方法名") 提交, 可以唤醒 mutation 中的方法

  在 vue 的视图中可以通过 this.$store.dispatch('action 方法名'),触发 action 中的对应方法执行

 

mutation 和 action 的关系图如下:

 

 

过滤器(格式化)

1. 价格后面加上符号‘元’。

 

2. 价格后面的单位也要动态的传值。(如:元、¥、$)

代码:

复制代码
<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <title> 过滤器</title>
    <script src="bli/vue.js"></script>
</head>
<body>
<div id="app">
    <input type="text" v-model="price">
    <!-- {{price | currency}} -->
    {{price | currency('美元') }}
</div>
</body>
<script src="js/14.main.js"></script>
</html>
复制代码

 

复制代码
// 过滤器
Vue.filter('currency',function(data,unit){
    data = data || 0;  // data 有值就等于 data, 没值就为 0.
    unit = unit || '元';  // unit 有值就等于 unit, 没值就为 '元'.
    return data + unit;
    // return data + '元';
});

new Vue({
el:'#app',
data:{
price:10,
},
});

复制代码

 

3. 毫米与米的转换。

 

4. 毫米与米的转换,保留两位小数。

 

 

自定义指令 - 基础配置

1. 自定义指令

 

2. 给只为 true 的元素定位(固定定位)

 

3. 加一个按钮,切换是否定位。

默认都是没有定住的。点击之后定住,再点击之后就是取消定住。

默认、取消定住

定住

4. 可以给很多按钮就加上。

默认、取消定位

定位

自定义指令 - 配置传参及修饰符

以上例子只能定位到左上角,不够灵活。位置应该动态传参。

1. 定位到右下角:

打印 var position = binding.modifiers;

console.log('position',position)  // position {bottom: true, right: true}

运行结果:已定位到右下角

2. 定位到左下角,只要改一个值即可。

 

3. 让一些卡片样式有所不同,突出。

获取该值(:true), 设置样式。

 

 

 

混合 mixins

1. 点击切换显示隐藏。

默认不显示 div.

点击后显示 div, 再次点击有隐藏 div.

 

 

2. 鼠标移入、移出切换显示隐藏。

默认、移出

移入:

 

 

 

3. 点击显示的 div 应该有个可以关闭的按钮。

注意:这两个组件有好多重复的代码!

点击后隐藏 div

 

混合 mixins(相同的代表放在一起)

功能是一样的。注意:自己写的会覆盖 mixins 的。

 

 

 

插槽 slots

1. 定义一个样式

 

2. 内容都是相同的。动态传参(插槽)

 

3. 如果头部、底部都要动态传参呢???定义 name!!!

 

4. 指定默认值。

 

在 Vue 的项目中使用了 Vue-Router,当某个路由有子级路由时,如下写法:

如果写法是如上的写法,就会报出如下警告:
[vue-router] Named Route 'home' has a default child route. When navigating to this named route (:to="{name:'home'"), the default child route will not be rendered. Remove the name from this route and use the name of the default child route for named links instead.

解决办法

因为当某个路由有子级路由的时候,这时候父级路由需要一个默认的路由,所以父级路由不能定义name属性,SO 解决办法是:即去除父级的name属性即可。