9

Vue.js基础总结

一、Vue使用介绍

Vue不支持IE8,因为使用了ES5的很多特性。可以直接通过script标签来引入vue.js,有开发版本和生产版本,开发版本一般我们在开发项目的时候引入,当最后开发完成上线的时候引入生产版本,开发版本没有压缩的,并且有很多提示,而生产版本全部删掉了。开发版本可以使用vue-devtools检查代码,生产版本不可以使用vue-devtools。

二、vue-router实践练习

1、传参及获取传参

通过$route获取相应参数
<div id="app">
  <div>
    <router-link to="/user/jack?age=20">jack</router-link>
    <!--另一种传参方式-->
    <!--<router-link :to="name:'user',params:{name:'jack'},query:{age:20}">jack</router-link>-->
    <router-link to="/user/midy?age=35">midy</router-link>  //通过to传递参数
  </div>
  <div>
    <router-view></router-view>
  </div>

</div>
<script src="https://cdn.bootcss.com/vue/2.5.13/vue.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.js"></script>
<script>
    var routes = [
        {
          path:'/user/:name',  //动态获取参数
          component:{
            template:`
              <div>
                <h1>我叫: {{$route.params.name}}</h1>   // 符号'/'后面的用params获取
                <h1>我今年: {{$route.query.age}} 岁。</h1> // 符号'?'后面的用query获取
              </div>
            `
          }
        }
      ];

      var router = new VueRouter({
        routes: routes
      })

      new Vue({
        el:"#app",
        router: router,
      })
</script>

2、子路由

路由中设置children,其也是一个数组
<div id="app">
  <div>
    <router-link to="/user/jack">jack</router-link>
    <router-link to="/user/midy">midy</router-link>
  </div>
  <div>
    <router-view></router-view>
  </div>

</div>
<script src="https://cdn.bootcss.com/vue/2.5.13/vue.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.js"></script>
<script>

      var routes = [
        {
          path:'/user/:name',
          component:{
            template:`
              <div>
                <h1>我叫: {{$route.params.name}}</h1>
                //方法一:动态绑定路由,to值为动态字符串拼接,比如:" /user/jack/more "
                <router-link :to="'/user/'+ $route.params.name +'/more'">显示更多 
                //方法二:动态绑定路由,to值写死,加上append属性,表示在当前路由上追加一个'more'
                <!--<router-link to="more" append>显示更多 -->                 
                </router-link>
                <router-view></router-view>
              </div>
            `
          }, 
          //定义子路由
          children:[
            {
              path:'more',
              component:{
                template:`
                  <div>
                   <p>我是 {{$route.params.name}},以下是我的更多信息。</p>
                   <p>哈哈哈哈哈哈~~~~</p>
                  </div>
                `
              }
            }
          ]
        }
      ];

      var router = new VueRouter({
        routes: routes
      })

      new Vue({
        el:"#app",
        router: router,
      })

 </script>
    

3、手动访问和传参

this.router.push()方法
<div id="app">
  <div>
    <router-link to="/home">主页</router-link>
    <router-link to="/user/jack">jack</router-link>
    <router-link to="/user/midy">midy</router-link>
    <button @click="surf">路由自动访问</button>
  </div>
  <div>
    <router-view></router-view>
  </div>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.13/vue.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.js"></script>
<script>

  var routes = [
    {
      path:'/home',
      component:{
        template: `
          <div><h1>我是首页!</h1></div>
        `
      }
    },
    {
      path:'/user/:name',
      name:'user',   //定义name属性,供下面的" this.router.push "使用
      component:{
        template:`
          <div>
            <h1>我叫: {{$route.params.name}}</h1>
            <router-link :to="'/user/'+ $route.params.name +'/more'">显示更多
            </router-link>
            <router-view></router-view>
          </div>
        `
      },
      children:[
        {
          path:'more',
          component:{
            template:`
              <div>
               <p>我是 {{$route.params.name}},以下是我的更多信息。</p>
               <p>哈哈哈哈哈哈~~~~</p>
              </div>
            `
          }
        }
      ]
    }
  ];

  var router = new VueRouter({
    routes: routes
  })

  new Vue({
    el:"#app",
    router: router,
    methods:{
      surf () {
        //setTimeout函数体内最好不使用箭头函数,因为this指向容易混淆
        setTimeout(function(){
          this.router.push('/home');
          setTimeout(function(){
            //动态传参,其中name代表的是路由的'name'属性值,params是传递参数
            this.router.push({name:'user',params:{name:'jack'}})
          },2000)
        },2000)
      }
    }
  })
</script>

4、命名视图

给router-view定义name属性
<div id="app">
  <div>
    <router-link to="/user">用户管理</router-link>
    <router-link to="/post">帖子管理</router-link>
  </div>
  <div>
    //分别为router-view 定义name属性,在下面定义显示内容
    <router-view name="sidebar"></router-view>  
    <router-view name="content"></router-view>
  </div>

</div>
<script src="https://cdn.bootcss.com/vue/2.5.13/vue.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.js"></script>
<script>

  var routes = [
    {
      path:'/user',
      //注意这里的components,分别定义两个router-view显示内容
      components: {
        //sidebar的router-view
        sidebar:{
          template:`
            <ul>
              <li>用户1</li>
              <li>用户2</li>
            </ul>
          `
        },
        //content的router-view
        content:{
          template:`
            <div>用户内容区域</div>
          `
        }
      }
    },
    {
      path:'/post',
      //注意这里的components,分别定义两个view显示内容
      components:{
        sidebar:{
          template:`
            <ul>
              <li>帖子1</li>
              <li>帖子2</li>
            </ul>
          `
        },
        content:{
          template:`
            <div>帖子内容区域</div>
          `
        }
      }
    }
  ];

  var router = new VueRouter({
    routes: routes
  })

  new Vue({
    el:"#app",
    router: router,
  })

</script>

5、导航钩子

实现的功能:如果用户在未登录状态下访问"/post"或"/post/more"页面,则会跳转到"/login"页面.
//方法一:通过判断路由的方式
<div id="app">
  <div>
    <router-link to="/">主页</router-link>
    <router-link to="/login">登录</router-link>
    <router-link to="/post">帖子管理</router-link>
    <router-view></router-view>
  </div>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.13/vue.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.js"></script>
<script>

  var routes = [
    {
      path:'/',
      component: {
        template:`
          <div>
            <h1>首页</h1>
          </div>
        `
      }
    },
    {
      path:"/login",
      component:{
        template:`
          <div><h2>登录</h2></div>
        `
      }
    },
    {
      path:'/post',
      component:{
        template:`
          <div>
            <h1>帖子1</h1>
            <router-link to="more" append>查看更多</router-link>
            <router-view></router-view>
          </div>
        `
      },
      children:[
        {
          path:'more',
          component:{
            template:`
            <h3>我是更多信息!</h3>
          `
          }
        }
      ]
    }
  ];

  var router = new VueRouter({
    routes: routes
  })

  router.beforeEach(function(to,from,next){
    console.log(to)
    var logged_in = false;
    //some() 方法用于检测数组中的元素是否满足指定条件,如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测.
    //to.matched返回的是数组。
    if(!logged_in && to.matched.some(function(val){return val.path == '/post'})){
        this.router.push("/login")
    }
    else{
      next()
    }
  })

  new Vue({
    el:"#app",
    router: router,
  })

</script>

//方法二:在路由中设定meta属性
<div id="app">
  <div>
    <router-link to="/">主页</router-link>
    <router-link to="/login">登录</router-link>
    <router-link to="/post">帖子管理</router-link>
    <router-view></router-view>
  </div>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.13/vue.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.js"></script>
<script>

  var routes = [
    {
      path:'/',
      component: {
        template:`
          <div>
            <h1>首页</h1>
          </div>
        `
      }
    },
    {
      path:"/login",
      component:{
        template:`
          <div><h2>登录</h2></div>
        `
      }
    },
    {
      path:'/post',
      //设定meta属性,指定"是否需要登录"
      meta:{
        login_required: true
      },
      component:{
        template:`
          <div>
            <h1>帖子1</h1>
            <router-link to="more" append>查看更多</router-link>
            <router-view></router-view>
          </div>
        `
      },
      children:[
        {
          path:'more',
          component:{
            template:`
            <h3>我是更多信息!</h3>
          `
          }
        }
      ]
    }
  ];

  var router = new VueRouter({
    routes: routes
  })

  router.beforeEach(function(to,from,next){
    console.log(to)
    var logged_in = false;
    //some() 方法用于检测数组中的元素是否满足指定条件,如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测.
    //通过获取meta值判此页面是否需要登录后才可访问
    if(!logged_in && to.matched.some(function(item){return item.meta.login_required })){
        this.router.push("/login")
    }
    else{
      next()
    }
  })

  new Vue({
    el:"#app",
    router: router,
  })

</script>

三、易错知识点——组件

1、父组件向子组件传递信息时:

在html中定义或者绑定属性的时候要符合kebab-case规则
<div id="dr2">
    <!-- kebab-case in html -->
    <child2 my-message2="Hello, this is kebab-case message!"></child2>
</div>
在js中定义的属性名称如果是"camelCase"规则,则在html定义或者绑定value的时候要用"kebab-case"规则。
Vue.component("child2", {
    //在js中用驼峰命名法
    props: ["myMessage2"],
    template: "<div>myMessage2: {{myMessage2}}</div>"
});
注意:下图中的<child></child>才是字符串模板,是通过template生成的,在这里的props需要使用kebab-case形式,在js中使用camelCase形式。

图片描述

2、prop验证属性

注意:下图所说的"诸如data,computed 或methods等实例属性还无法使用",指的是子组件自身定义的data,computed,methods属性。而非父组件的相应属性。

图片描述

3、props中default属性

注意:使用default属性时,在父组件绑定的数据不需要再data函数中赋值。

在组件中的props中,针对String,Number类型中的default,直接对应值。其他类型的default是函数。(如果使用default属性,就不能加上required:true属性)如下:
//son组件的props属性
props:{
    msg:{
      type:String,
      default: "abc"
    },
    num:{
      type:Number,
      default:10
    },
    myObj:{
      type:Object,
      //default为函数
      default: function (){
        return {name:"joy"}
      }
    }
  }
  
  
//parent组件传递的值
<son :msg="msgFather"></son>
<script>
export default {
  name: "Parent",
  data() {
    //此处不需要定义msgFather的值
    return {};
  },
  components: {
    son
  }
};
</script>

4、作用域插槽

插槽的数据是子传父的!!!

注:在vue 2.5.0之前,"slot-scope"必须使用到template身上。如下:

//2.5.0之前写法——父组件
<template>
  <div class="parent">
    <h1>我是父亲!</h1>
    <son>
       //将slot和slot-scope属性放在template上
      <template slot="slot1" slot-scope="key">
        <h2 >{{ key.text}}</h2>
      </template>
      //slot-scope属性值可以使任意的,此处为"key"
      <template slot="slot2" slot-scope="key">
        <h2>{{key.text}}</h2>
      </template>
    </son>
  </div>
</template>


//2.5.0以后版本写——父组件
<template>
  <div class="parent">
  <h1>我是父亲!</h1>
  <son>
     //slot-scope属性值可以使任意的,此处为"key"
    <h2 slot="slot1" slot-scope="key">{{ key.text}}</h2>
    <h2 slot="slot2" slot-scope="key">{{key.text}}</h2>
  </son>
</div>
</template>

//对应的子组件
<template>
<div class="son">
  <slot name="slot1" text="slot111111"></slot>
  <slot name="slot2" text="slot222222"></slot>
</div>
</template>

5、动态组件

<template>
  <div class="big">
  //通过comonent标签的is属性绑定当前的view视图
    <component :is="currentView"> </component>
  </div>
</template>

<script>
  import small1 from "./small1"

  export default {
    name: "big",
    data(){
      return{
        //注意此处的small组件需要加引号
        currentView: 'small1'
      }
    },
    components:{
      small1
    }
  }
</script>

四、易错知识点——自定义指令

1、全局定义指令:directive!!!

全局指令需要在main.js中去定义,如下:
//mian.js,全局定义中用directive。
Vue.directive('focus',{
  inserted:function(el){
    el.focus();
  }
})

//hello.vue
<template>
  <div>
    //使用指令方式:v-*
    <input type="text" v-focus>
  </div>
</template   

2、局部定义指令:directives!!!

<template>
  <div class="big">
    <input type="text" v-focus>
  </div>
</template>
<script>
  export default {
    name: "hello",
    //注:局部定义指令需要用directives,与全局定义不同。
    directives:{
      focus:{
        inserted (el){
          el.focus();
        }
      }
    }
  }
</script>

五、易错知识点——路由

1、路由使用对象形式

//通过urlData.*获得相应值
<router-link :to="urlData.hello">helloworld</router-link>
<router-link :to="urlData.parent">parent</router-link>
<router-view/>

data(){
    return{
      urlData:{
        hello:'/',
        parent:'/parent'
      }
    }
  }

2、路由传递参数(常用此方法!!!)

首先,在router/index.js文件中:
export default new Router({
  routes: [
    {
      //冒号后面跟着参数
      path:'/parent/:father',
      name:'parent',
      component: parent
    }
  ]
})
然后在parent.vue组件
<template>
  <div class="parent">
  //这里通过$route.params.*获取传递过来的路由参数
  <h1>我是父亲:{{$route.params.father}}</h1>
</div>
</template>
<script>
    export default {
      //设置parent.vue组件的name属性,传递参数是需要用到name属性值
      name: "parent",
    }
</script>
最后,找到parent对应的路由设置组件,配置如下
//router-link的name属性对应的是parent.vue组件的name值.params是传递过去的路由参数
<router-link :to="{name:'parent',params:{father:1}}">parent</router-link>
注意:这样的传递参数方式,最后的路由形式为:'localhost:8080/parent/father/1'。这种事很常见的路由传递参数。

3、路由嵌套:children

在router/index.js文件中:
export default new Router({
  routes: [
    {
      path:"/",
      name:"HelloWorld",
      component:HelloWorld
    },
    {
      path:'/parent',
      name:'parent',
      //重定向,默认进来就显示father组件的内容,在parent组件路由中配置
      redirect:"/parent/father",
      component: parent,
      children:[
        {
        //这里的path不加'/',直接写名字即可,它会自动补全前面的路径
          path:'father',
          name:'father',
          component:Father
        },
        {
          path:'mother',
          name:'mother',
          component:Mother
        }
      ]
    }
  ]
})
在parent组件中:
//这里的to属性值要写完整的路径
<router-link to="/parent/father">father</router-link>
<router-link to="/parent/mother">mother</router-link>
<router-view></router-view>

4、路由高亮
(1)、被选中的路由会带有"router-link-exact-active 、router-link-active"样式,所以可以给激活状态的路由设置样式。

//添加激活样式
.router-link-active{color:red;}
注意:此时会有一个问题,对于首页路由"/",会在同级路由被选中的时候依然会带有router-ink-active类名,这时候需要做在首页路由做修改:
//在router-link上添加exact属性
<router-link to="/" exact>home</router-link>

(2)router-link-active这个激活类名比较长,对此,我们可以在router/index.js中进行全局配置:

export default new Router({
  //全局设置linkActiveClass为acitve,这样激活状态的class就会变为active,相应的样式就可以改为.active{color:red;}
  linkActiveClass:"active",
  routes: [
    {
      path:'/',
      name:HelloWorld,
      component:HelloWorld
    },
    {
      path:'/parent/:father',
      name:'parent',
      component: parent
    }
  ]
})

六、易错知识点——methods

(1)、箭头函数不可用

注意: 在methods属性中定义的方法不能使用箭头函数,因为此时的this指向的是window,而不是Vue实例。

(2)、

//此处直接调用事件,并没有'()'
<button @click="showSome">click me </button>

methods:{
    showSome :function (event){
       //得到的就是鼠标事件
        console.log(event)
    }
}

结果:
图片描述
(3)、

//此处直接调用事件,并加上'()',但是并没有参数传递![图片描述][4]
<button @click="showSome()">click me </button>

methods:{
    showSome :function (event){
    //这样得到event就是'undefined'
        console.log(event)
    }
}

结果:
图片描述

(4)、

//此处直接调事件,如果想获得鼠标事件,传递的参数必须是$event否则就不要传递参数了
<button @click="showSome($event)">click me </button>

methods:{
    showSome :function (event){
    //这样得到event就是'鼠标事件'
        console.log(event)
    }
}

结果:图片描述

!!! (5)、methods 和 computed 不同使用方式:

computed可以向methods一样传递参数:解决办法是使用闭包
//key是传递的参数
computed:{
    getTitle(key):function(){
        return function(){
            return key + "abc"
        }
    }
}

七、易错知识点——select默认选中

1、vue中设置select默认选中:v-model

<template>
  <div class="hello">
  //select上通过v-model绑定默认选中项
    <select name="" id="" v-model="city">
      <option value="" v-for="item in cityList" :value="item.value" v-text="item.city"></option>
    </select>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      cityList:[
        {value:"001",city:"南京市"},
        {value:"002",city:"深圳市"},
        {value:"004",city:"杭州市"},
        {value:"005",city:"北京市"},
        {value:"003",city:"上海市"},
      ],
      //通过city值设定默认选中城市
      city:"003"
    }
  }
}
</script>

结果如图所示:
图片描述

八、易错知识点——v-model

1、一般form表单会使用v-model比较多,实现数据的双向绑定


<input v-model="sth" />
<input v-bind:value="sth" v-on:input="sth = $event.target.value" />

要理解这行代码,首先你要知道 input 元素本身有个 oninput 事件,这是 HTML5 新增加的,类似 onchange ,每当输入框内容发生变化,就会触发 oninput ,把最新的value传递给 sth。进而实现了数据双向绑定。

总结:
在给元素添加v-model属性时,默认会把value作为元素的属性,然后把input 事件作为实时传递value的触发事件。

//子组件
Vue.component('currency-input', {
  template: `
    <span>
      <input
        @input="$emit('input', $event.target.value)">
        </span>
      `
})
//父组件中调用子组件
<currency-input v-model="price"></currentcy-input>
<!--上行代码是下行的语法糖-->
<currency-input :value="price" @input="price = arguments[0]"></currency-input>

九、v-for循环时在class名中添加变量

实现如下图的情况:

图片描述


<template>
    <div class="qq_face faceout">
        <a v-for="(value, key) in stack.faceData" :key="key" :title="value" :class="setClass(key)" @click="faceImgSel(value)">{{value}}</a>
        <!-- 将class值赋给方法,动态生成对象 -->
    </div>
</template>

export default {
  methods: {
    setClass(key) {
        let obj = {face: true}
        obj[`qqface${key}`] = true
        return obj
    }
  }
}


Miss_Ye
1.5k 声望157 粉丝

知识的价值不在于占有,而在于使用!