Vue入门-Java思路

189 阅读6分钟

本文参考狂神学Vue视频,做Java的应该比较容易听懂
webpack相当于maven
component组件相当于bean
export暴露方法相当于public暴露接口
vue-cli templates相当于archetype模板
import相当于@Autowired、@Resource导入依赖
slot插槽相当于定义变量

一、MVVM框架

M:model

数据层(存储数据及对数据的处理如增删改查)

V:view

视图层(UI用户界面)

VM:ViewModel

业务逻辑层(一切js可视为业务逻辑),及时修改,及时编译,双向绑定了View层和Model层

v-model双向绑定演示

1.1引入vue.js

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

1.2 html代码

<div id="app">
    输入的文本:<input type="text" v-model="message"> { {message} }
</div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data:{
            message: "123"
        }
    });
</script>

1.3 演示view的改变,导致model层的改变

image.png

二、vue的七大属性

  • el属性

    用来指示vue编译器从什么地方开始解析 vue的语法,可以说是一个占位符。

  • data属性

    用来组织从view中抽象出来的属性,可以说将视图的数据抽象出来存放在data中。

  • template属性

    用来设置模板,会替换页面元素,包括占位符。

  • methods属性

    放置页面中的业务逻辑,js方法一般都放置在methods中

  • render属性

    创建真正的Virtual Dom

  • computed属性

    用来计算并存于内存,相当于缓存

  • watch属性

    watch:function(new,old){}

    监听data中数据的变化

    两个参数,一个返回新值,一个返回旧值

三、vue的基本语法

注意:以下案例均在IDEA中运行,请在IDEA安装vue插件,并设置javascript为6.0+

3.1 v-if v-else=if v-else

<h1 v-if="type==='A'">A</h1>
<h1 v-else-if="type==='B'">B</h1>
<h1 v-else>C</h1>
data: {
    type: 'A'
}

3.2 v-for

<li v-for="(item,index) in items">{ {index} } { {item.message} }</li>
data: {
    items: [
        {message: 'kuansheng说java'},
        {message: 'kuansheng说vue'}
    ]
}

vue绑定事件

3.3 v-on绑定方法

<button v-on:click="sayHi">Click Me</button>
<script>
    var vm = new Vue({
        el:"#app",
        data:{
            msg333: "Hello"
        },
        methods:{
            sayHi:function(event){
                alert(this.msg333);
            }
        }
    });
</script>

3.4 v-model双向绑定

(1)单选框

<div id="app">
    性别:
    <input type="radio" value="男" v-model="sex">男
    <input type="radio" value="女" v-model="sex">女
    <br/>
    你选择了:{{sex}}
</div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data:{
            sex: ""
        }
    });
</script>

(2)下拉框

<div id="app">
    下拉框:
    <select v-model="selected">
        <option value="" disabled>---请选择---</option>
        <option>A</option>
        <option>B</option>
        <option>C</option>
    </select>
    { {selected} }
</div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data:{
            selected: "A"
        }
    });
</script>

v-bind 绑定数据

<div id="app">
    <input v-bind:value=message />
</div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data:{
            message: 'hello'
        }
    });
</script>

四、组件化构建

4.1 组件化的概念

组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。

4.2 构建一个简单的组件

<div id="app">
    <xbm v-for="item in items" :project="item"></xbm>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script>
    Vue.component("xbm",{
        props:['project'],
        template: '<li>{ {project} }</li>'
    });
    var vm = new Vue({
        el: "#app",
        data:{
            items:["java","vue","linux"],
            message: 'hello'
        }
    });
</script>

五、axios通讯

由于vue是一个视图层框架,并且作为严格遵守SOC(关注度分离原则)所以vue.js并不包括ajax通信功能,为了解决通信问题,作者单独开发了一个名叫vue-resouce的插件,不过在进入2.0版本后停止了对该插件的维护,并推荐了Axois框架。少用jquery,因为操作dom过于频繁。

模拟数据data.json

{
  "name": "xbm",
  "url": "www.baidu.com",
  "page": 1,
  "isNonProfit": true,
  "address": {
    "street": "含光门",
    "city": "陕西西安",
    "country": "中国"
  },
  "links":[{
    "name": "bilibili",
    "url": "https://space.bilibili.com/95256449"
  },
    {
      "name": "狂神说java",
      "url": "https://blog.kuanngstudy.com"
    },
    {
      "name": "百度",
      "url": "https://www.baidu.com/"
    }
  ]
}

html代码

<style>
    //解决闪烁问题
    [v-clock]{
        display:none;
    }
</style>
<div id="app" v-clock>
    <div>{{info.name}}</div>
    <div>{{info.address.city}}</div>
    <a v-bind:href="info.url">click me</a>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data(){
            return{
                info:  {
                    name:null,
                    url:null,
                    address:{
                        street:null,
                        city:null,
                        country:null
                    }
                }
            }
        },
        mounted(){//钩子函数 链式编程
            axios.get('../data.json').then(response=>(this.info=response.data));
        }
    });
</script>

使用钩子函数mounted方法,在vue实例挂载的时候将json里的数据,加到示例的data函数的info属性中,利用mounted会将el替换成实例下的el的特性,把数据渲染到我们的app中

六、computed计算属性

我们的vue对象中有一个属性,使用缓存来 将不经常变化的属性的结果缓存,下一次可以不用重复,直接从内存中调取,节省系统的资源开销 注意事项:

  • methods computed不能重名,重名之后会有优先级问题,method优先级高

特性:

  • 作用于缓存中,和mybatis十分相似,一旦内部有属性变化就会立刻刷新
<div id="app" v-clock>
    Now:{{getTime()}}
    Now2:{{getTime2}}
</div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data:{
            message:'123'
        },
        methods:{
            getTime:function(){
                return Date.now();
            }
        },
        computed:{
            getTime2:function(){
                this.message;
                return Date.now();
            }
        }
    });
</script>

七、插槽

<div id="app">
    <to_do>
        <to_title slot="to_title" v-bind:title="title"></to_title>
        <to_items slot="to_items" v-for="item in todoItems" v-bind:item="item">        </to_items>
    </to_do>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script>
    Vue.component("to_do",{
        template: '<div>' +
                    '<slot name="to_title"></slot>'+
                    '<ul>' +
                        '<slot name="to_items"></slot>'+
                    '</ul>'+
                  '</div>'
    });
    Vue.component("to_title",{
        props: ['title'],
        template: '<p>{{title}}</p>'
    });
    Vue.component("to_items",{
        props: ['item'],
        template: '<li>{{item}}</li>'
    });
    var vm = new Vue({
        el: "#app",
        data: {
            title: '课程列表',
            todoItems: ['kuansheng说java','kuansheng说vue']
        }
    });
</script>

八、自定义事件分发

<div id="app">
    <to_do>
        <to_title slot="to_title" v-bind:title="title"></to_title>
        <to_items slot="to_items" v-for="(item,index) in todoItems" v-bind:item="item"
                  :index="index" v-on:remove2="removeItem(index)"></to_items>
    </to_do>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script>
    Vue.component("to_do",{
        template: '<div>' +
                    '<slot name="to_title"></slot>'+
                    '<ul>' +
                        '<slot name="to_items"></slot>'+
                    '</ul>'+
                  '</div>'
    });
    Vue.component("to_title",{
        props: ['title'],
        template: '<p>{{title}}</p>'
    });
    Vue.component("to_items",{
        props: ['item','index'],
        template: '<li>{ {item} } <button @click="remove">删除</button></li>',
        methods:{
            remove:function (index) {
                this.$emit('remove2',index);
            }
        }
    });
    var vm = new Vue({
        el: "#app",
        data: {
            title: '课程列表',
            todoItems: ['A','B','C','D']
        },
        methods:{
            removeItem:function(index){
                this.todoItems.splice(index,1);
            }
        }
    });
</script>

img

九、第一个vue-cli

先安装node.js(www.runoob.com/nodejs/node…)

  • 再安装vue-cli,管理员打开cmd,运行一下命令

    npm install vue-cli -g 或 cnpm install vue-cli -g(推荐使用这个方法)

  • 初始化第一个vue项目,在项目安放目录下运行一下命令

    vue init webpack myvue(项目名称)

  • 进入项目中

    cd myvue

  • 安装依赖

    npm install

  • 启动命令

    npm run dev

十、webpack学习使用

作用是把ES6(少数浏览器支持,但开发必须用ES6)规范的代码打包编译成ES5(大多数浏览器支持)规范的代码运行。

  • node.js遵循commons.js规范

    export 暴露接口

    import引用接口

    require加载模块

  • 安装

    npm install webpack -g

    npm install webpack-cli -g

10.1 使用webpack

  • 1.创建项目

  • 2.创建一个名为modules的目录,用于存放JS模块等资源文件

  • 3.在modules目录下创建模块文件,如hello.js,用于编写js模块相关代码

    //暴露一个方法
    exports.sayHi = function() {
        document.write("<h1>hello</h1>")
    }
    exports.sayHi2 = function() {
        document.write("<h1>hello</h1>")
    }
    exports.sayHi3 = function() {
        document.write("<h1>hello</h1>")
    }
    
  • 4.在modules目录下创建main.js入口文件
var hello = require("./hello");
hello.sayHi();
hello.sayHi2()
  • 5.在根目录下创建 webpack.config.js 打包文件
module.exports = {
    //入口
    entry: './modules/main.js',
    //输出
    output: {
        filename: './js/bundle.js'
    }
};
  • 6.输入打包命令 webpack

  • 7.创建index.html文件。引入打包后的js
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--引入打包后的js-->
<script src="dist/js/bundle.js"></script>
</body>
</html>

十一、vue路由

vue-router (axios的安装同vue-router)

  • 安装(在项目位置)

    npm install vue-router —save-dev

  • 引用vue-router

import Vue from 'vue'
import App from './App'
import VueRouter from 'vue-router'
Vue.config.productionTip = false
//显示声明vue-router
Vue.use(VueRouter);
/* eslint-disable no-new */
new Vue({
  el: '#app',
  components: { App },
  template: '<App/>'
})
  • 路由使用演示

(1)创建两个组件,Main和Content

<template>
    <h1>首页</h1>
</template>
<script>
    export default {
        name: "Main"
    }
</script>
<style scoped>
</style>
<template>
    <h1>内容页</h1>
</template>
<script>
    export default {
        name: "Content"
    }
</script>
<style scoped>
</style>

(2)创建一个路由文件夹router ,在其下面创建一个路由配置文件index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
//导入组件
import Content from "../components/Content";
import Main from "../components/Main";
//显示声明
Vue.use(VueRouter);
//配置导出路由
export default new VueRouter({
  routes: [
    {
      //路由路径
      path: '/content',
      //名字,自己取(可省略)
      name: 'content',
      //跳转组件
      component: Content
    },
    {
      //路由路径
      path: '/main',
      //名字,自己取(可省略)
      name: 'main',
      //跳转组件
      component: Main
    }
  ]
});

(3) main.js中配置路由

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router' //自动扫描里面的路由
Vue.config.productionTip = false
//显示声明vue-router
Vue.use(router);
/* eslint-disable no-new */
new Vue({
  el: '#app',
  //配置路由
  router,
  components: { App },
  template: '<App/>'
})

(4) app.vue中展示不同的组件

<template>
  <div id="app">
    <h1>vue-router</h1>
    <router-link to="/main">首页</router-link>
    <router-link to="/content">内容页</router-link>
    <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>

十二、vue+elementUI

  • 创建项目

    //初始化项目

    vue init webpack hello-vue

    //进入项目

    cd hello-vue

    //安装 vue-router

    npm install vue-router —save-dev

    //安装elementUI

    npm i element-ui -s

    //安装依赖

    npm install

    //启动测试

    npm run dev

  • 登录页面 login.vue

<template>
  <div class="login-container">
    <el-form :model="ruleForm2" :rules="rules2"
             status-icon
             ref="ruleForm2"
             label-position="left"
             label-width="0px"
             class="demo-ruleForm login-page">
      <h3 class="title">系统登录</h3>
      <el-form-item prop="username">
        <el-input type="text"
                  v-model="ruleForm2.username"
                  auto-complete="off"
                  placeholder="用户名"
        ></el-input>
      </el-form-item>
      <el-form-item prop="password">
        <el-input type="password"
                  v-model="ruleForm2.password"
                  auto-complete="off"
                  placeholder="密码"
        ></el-input>
      </el-form-item>
      <el-checkbox
        v-model="checked"
        class="rememberme"
      >记住密码</el-checkbox>
      <el-form-item style="width:100%;">
        <el-button type="primary" style="width:100%;" @click="handleSubmit" :loading="logining">登录</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
    export default {
        data(){
            return {
                logining: false,
                ruleForm2: {
                    username: 'admin',
                    password: '123456',
                },
                rules2: {
                    username: [{required: true, message: 'please enter your account', trigger: 'blur'}],
                    password: [{required: true, message: 'enter your password', trigger: 'blur'}]
                },
                checked: false
            }
        },
        methods: {
            handleSubmit(event){
                this.$refs.ruleForm2.validate((valid) => {
                    if(valid){
                        this.logining = true;
                        if(this.ruleForm2.username === 'admin' &&
                            this.ruleForm2.password === '123456'){
                            this.logining = false;
                            sessionStorage.setItem('user', this.ruleForm2.username);
                            this.$router.push({name: 'main',params:{username:this.ruleForm2.username} });
                        }else{
                            this.logining = false;
                            this.$alert('username or password wrong!', 'info', {
                                confirmButtonText: 'ok'
                            })
                        }
                    }else{
                        console.log('error submit!');
                        return false;
                    }
                })
            }
        }
    };
</script>
<style scoped>
  .login-container {
    width: 100%;
    height: 100%;
  }
  .login-page {
    -webkit-border-radius: 5px;
    border-radius: 5px;
    margin: 180px auto;
    width: 350px;
    padding: 35px 35px 15px;
    background: #fff;
    border: 1px solid #eaeaea;
    box-shadow: 0 0 25px #cac6c6;
  }
  label.el-checkbox.rememberme {
    margin: 0px 0px 15px;
    text-align: left;
  }
</style>
  • 首页Main
<template>
  <el-container style="height: 500px; border: 1px solid #eee">
    <el-aside width="200px" style="background-color: rgb(238, 241, 246)">
      <el-menu :default-openeds="['1', '3']">
        <el-submenu index="1">
          <template slot="title">用户管理</template>
          <el-menu-item-group>
            <el-menu-item index="1-1"><router-link to="/user/list">用户列表</router-link></el-menu-item>
             <!-- :to 绑定,name:路由器中的名字,params:传参 -->
            <el-menu-item index="1-2"><router-link :to="{name: 'userProfile',params: { id: 123 } }">个人信息</router-link></el-menu-item>
          </el-menu-item-group>
        </el-submenu>
        <el-submenu index="2">
          <template slot="title">系统管理</template>
          <el-menu-item-group>
            <el-menu-item index="2-1">系统查看</el-menu-item>
            <el-menu-item index="2-2">系统设置</el-menu-item>
          </el-menu-item-group>
        </el-submenu>
      </el-menu>
    </el-aside>
    <el-container>
      <el-header style="text-align: right; font-size: 12px">
        { {username} }
      </el-header>
      <el-main>
        <router-view></router-view>
      </el-main>
    </el-container>
  </el-container>
</template>
<style>
  .el-header {
    background-color: #B3C0D1;
    color: #333;
    line-height: 60px;
  }
  .el-aside {
    color: #333;
  }
</style>
<script>
    export default {
        props: ['username'],
        name: "Main"
    };
</script>
  • 404页面
<template>
  <div>
    <h1>404,你找的页面走丢了!</h1>
  </div>
</template>
<style>
  .el-header {
    background-color: #B3C0D1;
    color: #333;
    line-height: 60px;
  }
  .el-aside {
    color: #333;
  }
</style>
<script>
    export default {
        name: "NotFound"
    };
</script>
  • 用户列表页面 user/UserList
<template>
    <h1>用户列表 </h1>
</template>
<script>
    export default {
        name: "UserList"
    }
</script>
<style scoped>
</style>
  • 用户个人信息页面 user/UserProfile
<template>
  <h1>用户个人信息{ {id} }</h1>
</template>
<script>
    export default {
        props: ['id'],
        name: "UserProfile",
        //路由钩子
        beforeRouteEnter:(to, from, next)=>{
            console.log("进入路由之前");
            next(vm=>{
                vm.getData()
            });
        },
        //路由钩子
        beforeRouteLeave:(to, from, next) => {
            console.log("离开路由之前");
            next();
        },
        methods:{
            //模拟获取后台数据
            getData:function () {
                this.axios({
                    method: 'get',
                    url: 'http://localhost:8080/static/mock/data.json'
                }).then(function (response){
                    console.log(response.data);
                })
            }
        }
    }
</script>
<style scoped>
</style>
  • 路由index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import Main from "../components/Main";
import Login from "../components/Login"
import UserList from "../components/user/UserList";
import UserProfile from "../components/user/UserProfile";
import NotFound from "../components/NotFound";
Vue.use(VueRouter);
export default new VueRouter({
  mode: 'history',//去掉url中的/#/
  routes:[
    {
      path: '/main/:username',
      name: 'main',
      component: Main,
      props: true,
      children: [
        {
          path: '/user/list',
          component: UserList,
          props: true
        },
        {
          path: '/user/profile/:id',//id为参数 
          name: 'userProfile',
          component: UserProfile,
          props: true
        }
      ]
    },
    {
      path: '/login',
      name: 'login',
      component: Login
    },
    {
      path: '*',
      component: NotFound
    }
  ]
});
  • main.js代码
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App'
import router from './router'
//需要先安装axios  npm install axios
import axios from 'axios'
//需先安装vue-axios npm install --save axios vue-axios
import VueAxios from "vue-axios";
Vue.use(VueAxios, axios)
Vue.use(router);
Vue.use(ElementUI);
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>',
  render: h => h(App)
})
  • 模拟数据 data.json static/mock/data.json
{
  "name": "天道佩恩",
  "url": "www.baidu.com",
  "page": 1,
  "isNonProfit": true,
  "address": {
    "street": "含光门",
    "city": "陕西西安",
    "country": "中国"
  },
  "links":[{
    "name": "bilibili",
    "url": "https://space.bilibili.com/53326010"
  },
    {
      "name": "狂神说java",
      "url": "https://blog.kuanngstudy.com"
    },
    {
      "name": "百度",
      "url": "https://www.baidu.com/"
    }
  ]
}
  • App.vue
<template>
  <div id="app">
      <!--显示路由的页面-->
    <router-view></router-view>
  </div>
</template>
<script>
export default {
  name: 'App',
  components: {
  }
}
</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>

引入js

<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>

如门示例

<div id="app">
    输入的文本:<input type="text" v-model="message"> {{message}}
</div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data:{
            message: "hello world"
        }
    });
</script>
<li v-for="(item,index) in items">{ {index} } { {item.message} }</li>
data: {
    items: [
        {message: 'kuansheng说java'},
        {message: 'kuansheng说vue'}
    ]
}

引入axios

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

export暴露方法,有点跟java的public类似