VUE 快速入门 —— 零碎知识

VUE 快速入门

作者 尤雨溪

Vue 的核心库只关注视图层,方便与第三方库或既有项目整合。

原则:关注点分离(Separation of concerns,SOC)

特点:MVVM模式、虚拟DOM操作

网络通信:axios (通俗的即ajax,只支持ES6)

页面跳转:vue-router

状态管理:vuex

Vue-UI:ice.work、layUI等

一、初始Vue

使用idea开发工具

安装插件:vue.js

生命周期

1、MVVM

MVVM是Model-View-ViewModel的简写。它本质上就是MVC 的改进版。

MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大优点

  • 低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
  • 可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
  • 独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成xaml代码。
  • 可测试。界面素来是比较难于测试的,测试可以针对ViewModel来写。

2、vue基本语法

v-开头的是vue里面的命令

  • v-cloak:在数据加载之前都会将该元素进行隐藏,直至数据加载完之后,该属性会消失。能够解决插值表达式的闪烁问题。

  • v-text:会覆盖标签内的原本内容。没有 插值表达式形式添加数据的闪烁问题。

    注意:插值表达式只会替换自己的占位符换成对应数据,而v-text被解析之后会将标签内的数据全部给覆盖掉。

  • v-html:会覆盖标签内的原本内容。会把数据内容当成html去解析。

  • v-bind:可简写成英文的冒号‘:’。是Vue中,提供绑定属性的指令,会将绑定属性的内容解析成js的表达式去执行,可写成合法的表达式。数据单向绑定M->V

  • v-on:可简写成英文的冒号‘@’。事件绑定机制

  • v-model:可实现数据的双向绑定 M <-> V,只能运用于表单中

  • v-for:顺序遍历,可遍历普通数组(item,i)、对象数组(item,i)、对象(val,key,i)、数字迭代(从1开始)遍历的时候必须绑定一个key属性,以标识唯一身份

  • v-if:当值为false时,元素被彻底删除;为true时元素则被创建(有较高的性能消耗)

  • v-else-if:与v-if/v-else搭配使用

  • v-else:与v-if搭配使用

  • v-show:当值为false时,元素增加样式display:none;为true时改变样式,使元素被重新显示(有较高的初始渲染消耗)

  • ref :将该标签绑定起来 ref='name',在vue中可以通过 this.$refs.name 可以获取到那个为name的标签

3、组件 component

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>组件</title>
</head>
<body>

<div id="app" v-cloak>
    <!--定义了一个名为hero的组件,模板为'<li>{{option}}</li>'
        props是该组件的属性,只为该组件使用,通过v-for遍历出来的item与属性绑定
        可进行数据传输通信
    -->
    <hero v-for="item in items" v-bind:option="item"></hero>
</div>

<script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
<script>

    Vue.component("hero",{
        props: ['option'],
        template: '<li>{{option.name}} &nbsp; {{option.age}} &nbsp; {{option.sex}}</li>'
    });

    var vm = new Vue({
        el:"#app",
        data:{
            items: [
                {name:"heroC",age:21,sex:"男"},
                {name:"yikeX",age:21,sex:"女"}
            ]
        }
    });
</script>
</body>
</html>

4、网络通信 axios

只支持 ES6

特性:

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF

使用:

{
  "name": "heroC",
  "url": "www.baidu.com",
  "page": 1,
  "isNonProfit": true,
  "address": {
    "street": "西三环路",
    "city": "成都",
    "country": "中国"
  },
  "links": [
    {
      "name": "bilibili",
      "url": "https://www.bilibili.com/"
    },
    {
      "name": "翻译",
      "url": "https://fanyi.baidu.com"
    }
  ]
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<style>
    [v-cloak]{
        display: none;
    }
</style>
<body>

<div id="app" v-cloak>
    <a :href="info.links[0].url">bilibili</a>
</div>

<script src="https://cdn.bootcss.com/axios/0.19.2/axios.min.js"></script>
<script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
<script>
    var vm = new Vue({
        el:"#app",
        data(){
            return{
                // info接收ajax请求返回的数据
                info:null
            }
        },
        // mounted 在vue生命周期中可以用于ajax请求的钩子函数 axios只支持ES6
        mounted(){
            // 将响应过来的数据返回到data函数的info中
            axios.get('../data.json').then(response=>(this.info = response.data));
        }
    });
</script>
</body>
</html>

5、计算属性 computed

<div id="app" v-cloak>
    <h3>{{currentTime1()}}</h3>
    <h3>{{currentTime2}}</h3>
</div>

<script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
<script>
    var vm = new Vue({
        el:"#app",
        data:{
            message:"hello,Vue!"
        },
        methods:{
            /*currentTime1 是一个方法,即使不刷新页面,时间戳也会在后台刷新*/
            currentTime1: function () {
                return Date.now();
            }
        },
        /*计算属性,将第一次加载的数据缓存在currentTime2中,不刷新页面数据就不会改变*/
        computed:{
            /*currentTime2 是一个属性,在一个加载完整的页面中,如果该属性的方法发生变化,那么数据也会更新一次*/
            currentTime2: function () {
                return Date.now();
            }
        }
    });
</script>

在浏览器后台调用方法与计算属性的结果:

可知,计算属性是一个缓存的作用,第一次加载的数据是多少该属性就一直缓存的多少。而方法,调用一次就执行一次。

计算属性的作用就是将不经常发生变化的计算结果进行缓存,以节约系统开销。

6、插槽 slot

<style>
    [v-cloak]{
        display: none;
    }
</style>
<body>

<div id="app" v-cloak>
<todo>
    <!--todo-title组件与插槽stitle绑定,并将app中的title属性与该组件的属性绑定-->
    <todo-title slot="stitle" :todotitle="title"></todo-title>
    <!--todo-item组件与插槽sitem绑定,并将app中的items属性遍历的每一项与该组件的属性绑定-->
    <todo-item slot="sitem" v-for="item in items" :todoitem="item"></todo-item>
</todo>
</div>

<script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
<script>

    Vue.component("todo",{
        template: '<div>\
                      <slot name="stitle"></slot>\
                      <ul>\
                           <slot name="sitem"></slot>\
                      </ul>\
                   </div>'
    });
    Vue.component("todo-title",{
        props: ['todotitle'],
        template: '<div>{{todotitle}}</div>'
    });
    Vue.component("todo-item",{
        props: ['todoitem'],
        template: '<li>{{todoitem}}</li>'
    });

    var vm = new Vue({
        el:"#app",
        data: {
            title: 'heroC',
            items: [
                '真好',
                '真厉害',
                '真棒'
            ]
        }
    });
</script>
</body>

7、自定义事件 this.$emit()

点击删除按钮,可删除该元素

this.$emit('自定义事件名',参数)

<div id="app" v-cloak>
    <todo>
        <todo-title slot="stitle" :todotitle="title"></todo-title>
        <!--绑定索引,将vm实例中的removeIndex方法,绑定该组件自定义的removeon方法,
			因此,就可以是实现该组件使用vm实例的方法了-->
        <todo-item slot="sitem" v-for="(item,index) in items" :todoitem="item"
                   :index="index" @removeon="removeIndex"></todo-item>
    </todo>
</div>

<script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
<script>

    Vue.component("todo",{
        template: '<div>\
                      <slot name="stitle"></slot>\
                      <ul>\
                           <slot name="sitem"></slot>\
                      </ul>\
                   </div>'
    });
    Vue.component("todo-title",{
        props: ['todotitle'],
        template: '<div>{{todotitle}}</div>'
    });
    Vue.component("todo-item",{
        props: ['todoitem','index'],
        template: '<li>{{todoitem}} <button @click="remove">删除</button></li>',
        methods: {
            remove: function (index) {
                // 事件分发 this.$emit('自定义事件名',参数)
                this.$emit('removeon',index);
            }
        }
    });

    var vm = new Vue({
        el:"#app",
        data: {
            title: 'heroC',
            items: [
                '真好',
                '真厉害',
                '真棒'
            ]
        },
        methods: {
            removeIndex(index){
                this.items.splice(index,1);
            }
        }
    });
</script>

二、Vue-cli

1、安装vue-cli

安装nodejs 搭建环境

安装nodejs,cmd运行node -vnpm -v观察有没有版本信息,如果有版本信息,说明环境搭建好了

在cmd控制窗口安装:

安装cnpm,国内的镜像下载命令,npm install cnpm -g 全局安装cnpm

安装路径:C:\Users\Administrator\AppData\Roaming\npm

安装vue-cli

cnpm install vue-cli -g

安装完成 vue list

vue list 可检查是否安装成功

2、第一个Vue-cli项目

  • 在自己的项目文件夹下,通过cmd控制窗口,初始化一个项目

vue init webpack <项目名>

  • 初始化项目

npm install

初始化项目之后,在该项目下会多一个node_modules文件夹

  • 以管理员身份使用idea打开项目

  • vue项目打包发布

npm run dev

三、webpack

可将ES6规范的代码打包编译成ES5规范的代码。

  • 使用webpack 就可以将项目打包了 webpack --watch 可监听更改的文件,然后自动打包

四、vue-router 路由

安装vue-router

npm install vue-router --save-dev

路由模式

页面跳转案例

main.js 全项目的入口

import Vue from 'vue'
import App from './App'
// 导入router文件夹下的js文件,该文件夹下如果以index.js命名,会自动识别,如果没有以index.js命名,需要指定导入的是哪个js
import Router from './router'

Vue.config.productionTip = false;

new Vue({
  el: '#app',
  // router 配置路由的属性
  router: Router,
  components: { App },
  template: '<App/>'
})

App.vue 主页

<template>
  <div id="app">
    <h1>heroC</h1>
    <!--router-link 类似a标签,是router专用-->
    <router-link to="/main">首页</router-link>
    <router-link to="/content">内容页</router-link>
    <!--router-view 作用是将router-link 路径绑定的组件展示到router-view中-->
    <router-view></router-view>
  </div>
</template>

<script>

export default {
  name: 'App',

}
</script>

<!--全局样式-->
<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

Main.vue

<template>
  <h2>首页</h2>
</template>

<script>
    export default {
        name: "Main"
    }
</script>

<style scoped>

</style>

Content.vue

<template>
  <h2>内容页</h2>
</template>

<script>
    export default {
        name: "Content"
    }
</script>

<!--scoped 表示style只在该组件中有效-->
<style scoped>

</style>

router文件夹下的index.js

import VueRouter from "vue-router";
import Vue from "vue";
import Content from "../components/Content";
import Main from "../components/Main";

// 显示声明使用路由
Vue.use(VueRouter);

// 将路由配置暴露出去
export default new VueRouter({
  mode: 'history',
  routes: [
    {
      // 跳转Content组件的映射路径 '/content'  
      path: '/content',
      name: 'content',
      component: Content
    },
    {
      path: '/main',
      component: Main
    }
  ]
})

点击首页,会自动跳转到绑定路径的首页组件

五、Element UI

1、创建项目完整项目....

ElementUI文档

import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

要注意sass版本号:

"sass-loader": "^7.0.3",
"node-sass": "^4.13.1",

2、404 页面

<template>
    <h1>404, 你的页面走丢了...</h1>
</template>

<script>
    export default {
        name: "NotFound"
    }
</script>

<style scoped>

</style>
import VueRouter from "vue-router";
import Vue from "vue";
import Content from "../components/Content";
import Main from "../components/Main";
import NotFound from "../components/NotFound";

// 显示声明使用路由
Vue.use(VueRouter);

// 将路由配置暴露出去
export default new VueRouter({
  routes: [
    {
      path: '/content',
      name: 'content',  // 给路径取名字,可代替路径使用
      component: Content
    },
    {
      path: '/main',
      component: Main
    },
    {
        // 不匹配的路径走*,NotFound组件,404
      path: '*',
      component: NotFound
    }
  ]
})

3、路由钩子函数

在通过路由进入该组件之前,会执行beforeRouteEnter,在离开这个路由之后,执行beforeRouteLeave

六、axios 接收json数据 渲染到组件中

<template>
  <div>
    <table>
      <tr>
        <th>网址</th>
        <th>地址</th>
      </tr>
      <tr v-for="value in links">
        <td>{{value.name}}</td>
        <td><a :href="value.url">{{value.url}}</a></td>
      </tr>
    </table>
  </div>
</template>


<script>
    export default {
        name: "Content",
      data(){
        return{
          // info接收ajax请求返回的数据
          info:null,
          links: null,
        }
      },
        beforeRouteEnter(to, from, next){
          next(vm => {
            vm.getData();
          });
        },
      methods: {
          getData: function () {
            this.axios.get('../../static/data.json').then((response) => {
              this.info = response.data;
              this.links = response.data.links});
            /*this.axios.post('/data',this.info).then((response) => {
              console.log(response.data)});*/
          }
      }
  }
</script>

<!--scoped 表示style只在该组件中有效-->
<style scoped>

</style>

七、前端开发中遇见的问题

登录拦截问题

登录拦截问题

const router = new VueRouter({
  mode: 'history', // 设置为history,就不会在路由路径中出现#符号
  routes: [
    {
      path: '/main',
      name: 'main',
      props: true,
      meta:{
        requireAuth: true
      }, // 在需要拦截的请求中加入该meta属性,可以用于判断是否拦截该路由
      component: Main
    }
  ]
})

// 判断是否需要登录权限 以及是否登录
router.beforeEach((to, from, next) => {
  if (to.matched.some(res => res.meta.requireAuth)) {// 判断是否需要登录权限
    if (localStorage.getItem('username')) {// 判断是否登录
      next()
    } else {// 没登录则跳转到登录界面
      next({
        path: '/',
        query: {redirect: to.fullPath}
      })
    }
  } else {
    next()
  }
})

跨域请求访问问题

解决跨域问题

module.exports = {
  dev: {

    // Paths
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    // proxyTable是解决跨域的配置
    proxyTable: {
      '/api':{
        target:'http://127.0.0.1:8080', // 请求的地址,会在/api前面添加请求目的
        changeOrigin:true, // 开启允许跨域请求
        /*pathRewrite: {
          '^/api': '/' //如果请求路径中本身就有/api该属性不用配置。该属性的意思是将/api替换成/
        }*/
      }
    },
    
    // Various Dev Server settings
    host: 'localhost', // can be overwritten by process.env.HOST
    port: 8030, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
    autoOpenBrowser: false,
    errorOverlay: true,
    notifyOnErrors: true,
    poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
    ...
  }
  ...
}

前端发送json数据给后端乱码问题

解决前端发送数据乱码问题

this.axios({
    ...
    headers: {
        'Content-Type': 'application/json; charset=utf-8'
    } // 设置数据的格式,以避免后端接收到的json出现乱码
}

全局存储登录用户名问题

localstorage和sessionstorage的区别

localstorage(本地存储)则以文件的方式存储在本地,永久保存(不主动删除,则一直存在);

sessionstorage( 会话存储 ) ,临时保存,关掉该网站后,ssessionstorage就会被清除掉。

localStorage和sessionStorage只能存储字符串类型,对于复杂的对象可以使用ECMAScript提供的JSON对象的stringify和parse来处理

sessionStorage.setItem("username",this.form.username);
或者
localStorage.setItem("username",this.form.username);

接收后台json数据,将其中的一项数据封装为数组

比如:

json数据通过JSON.parse转换成前端对象之后

[{
    name: 'heroC',
    shouru: 38000,
    zhichu: 10000
},
{
    name: 'yikeX',
    shouru: 55000,
    zhichu: 20000
}]

将每一个属性的数组归为一组:

var data = [
    {
        name: 'heroC',
        shouru: 38000,
        zhichu: 10000
    },
    {
        name: 'yikeX',
        shouru: 55000,
        zhichu: 20000
    }];
// 类似于lamda表达式
data.map(r => r.name);
data.map(r => r.shouru);
data.map(r => r.zhichu);

解决tomcat部署vue项目后,刷新页面问题

在tomcat的web.xml中加入该配置即可:

<error-page>
    <error-code>404</error-code>
    <location>/index.html</location>
</error-page>

八、Echarts 、V-Charts

四川地图:

<template>
  <ve-map :data="chartData" :settings="chartSettings" :extend="chartExtend"></ve-map>
</template>

<script>
  export default {
    data () {
      this.chartSettings = {
        position: 'province/sichuan'
      }
      this.chartExtend = {
        legend:{show:false},
        color: false,
        backgroundColor:'#fff',
        visualMap: {
            min: 0,
            max: 15,
            text: ['High', 'Low'],
            realtime: false,
            calculable: true,
            inRange: {
                color: ['#fff','lightskyblue', 'yellow', 'orangered']
            }
        },
        tooltip: {
            trigger: 'item'
        }
      }
      return {
        chartData: {
          columns: ['位置', '店铺'],
          rows: [
            { '位置': '成都市', '店铺': 13 },
            { '位置': '绵阳市', '店铺': 12 },
            { '位置': '自贡市', '店铺': 0 },
            { '位置': '攀枝花市', '店铺': 0 },
            { '位置': '泸州市', '店铺': 0 },
            { '位置': '德阳市', '店铺': 0 },
            { '位置': '广元市', '店铺': 0 },
            { '位置': '遂宁市', '店铺': 0 },
            { '位置': '内江市', '店铺': 0 },
            { '位置': '乐山市', '店铺': 3 },
            { '位置': '资阳市', '店铺': 0 },
            { '位置': '宜宾市', '店铺': 2 },
            { '位置': '南充市', '店铺': 0 },
            { '位置': '达州市', '店铺': 0 },
            { '位置': '雅安市', '店铺': 0 },
            { '位置': '阿坝藏族羌族自治州', '店铺': 0 },
            { '位置': '甘孜藏族自治州', '店铺': 0 },
            { '位置': '凉山彝族自治州', '店铺': 0 },
            { '位置': '广安市', '店铺': 0 },
            { '位置': '巴中市', '店铺': 0 },
            { '位置': '眉山市', '店铺': 6 }
          ]
        }
      }
    }
  }
</script>
posted @ 2025-04-10 15:10  Vincezon  阅读(10)  评论(0)    收藏  举报