1 Vue

2 Node、NPM

  • NPM是Node提供的模块管理工具,可以非常方便地下载安装很多前端框架。

1、Node.js

2、NPM

  • Node.js自带了NPM,在控制台输入npm -v即可查看版本信息。

  • NPM默认的仓库地址在国外,速度较慢,建议设置到淘宝镜像。切换镜像比较麻烦,推荐使用切换镜像的工具:nrm。

  • 安装nrm,-g表示全局安装:

    npm install nrm -g
  • nrm ls:显示所有镜像。

  • nrm use [name]:使用指定镜像。

3 Vue快速入门

3.1 创建

1、新建空项目

图片说明

2、初始化

  • 在项目目录下执行命令:npm init
  • 项目中会多出一个文件:package.json(相当于XML配置文件)。

3、安装Vue

  • 在项目目录下执行命令:npm install vue —save
  • 项目中会多出一个文件:node_modules,其中就有Vue。

图片说明

  • 同时,package.json中也会增加Vue的依赖。

4、Hello Vue

    <!DOCTYPE html>
    <html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <!--Vue对象的HTML模板-->
    <div id="app">
        <h1>{{name}}</h1>

        <!--双向绑定:v-model-->
        <input type="text" v-model="num">
        <h1>{{num}}</h1>

        <!--v-on:事件名:定义事件-->
        <input type="button" value="num++" v-on:click="num++">
        <input type="button" value="num++" v-on:click="incre">
    </div>
    </body>
    <script src="node_modules/vue/dist/vue.js"></script>
    <script>
        // 初始化一个Vue实例
        const app = new Vue({
           el: "#app",  // element缩写,"#app"选择器
           data: {  // 定义数据模型
               name: "Hello Vue",
               num: 100
           },
            methods: {  // 定义方法
               incre() {
                   this.num++;
               }
            }
        });
    </script>
    </html>

3.2 生命周期、钩子函数

图片说明

  • 每个Vue实例在被创建时都要经过一系列的初始化过程:创建实例、装载模板、渲染模板等。

  • Vue为生命周期中的每个状态都设置了钩子函数(监听函数)。

  • 每当Vue实例处于不同的生命周期时,对应的函数就会被触发调用。

  • 常用:

    created() { // 实例化之后,渲染之前:获取数据
       // 1、获取数据:Ajax
       // 2、绑定数据:this.name = result
    }

3.3 指令

  • 指令是带有v-前缀的特殊特性。
  • 指令特性的预期值是:单个JavaScript表达式。
  • 指令的职责是:当表达式的值改变时,将其产生的连带影响,响应式的作用域DOM。

1、数据绑定

  • 花括号(会有闪烁问题)

    {{表达式}}
  • v-textv-html(没有闪烁问题)

    <h1>xxx<span v-text="name">默认值</span>xxx</h1>
  • v-model:双向绑定,用在表单元素中。

2、事件绑定:v-on@

  • 绑定事件。

  • 语法:

    v-on:事件名="函数名"
    @事件名="函数名"
  • 在响应函数里,可以指明使用event内置的参数对象。该对象表示当前事件,可以通过使用event.target.value来获得当前事件对象的value值。

    changeMajor(event) {
    this.msg = event.target.value;
    }
  • 可以使用data()中的数据进行数据传递:

    <template>
    <div>
      {{count}}
      <button type="button" @click="addBtn">add</button>
      <p>myStep: <input type="text" v-model="myStep"></p>
    </div>
    </template>
    <script>
    export default {
    name: 'HelloWorld',
    data () {
      return {
        count: 0,
        myStep: 1
      }
    },
    methods: {
      addBtn() {
        var myNum = this.myStep - 0;
        this.count += myNum;
      }
    }
    }
    </script>
  • 也可以直接在函数中进行传递数据:

    <template>
    <div>
      {{count}}
      <button type="button" @click="addBtn">add</button>
    </div>
    </template>
    <script>
    export default {
    name: 'HelloWorld',
    data () {
      return {
        count: 0,
      }
    },
    methods: {
      addBtn(step) {
        this.count += step;
      }
    }
    }
    </script>
  • Vue为v-on提供了事件修饰符:

    • .stop:阻止事件冒泡到父元素。
    • .prevent:阻止默认事件发生。
    • .capture:使用事件捕获模式。
    • .self:只有元素自身触发事件才执行(冒泡或捕获的都不执行)。
    • .once:只执行一次。
      v-on.click.prevent="num++:"
  • 按键修饰符:

    • @keyup.13@keyup.enter:回车事件。
    • ……
  • 组合按钮:

    • .ctrl.ctrl.67
    • .alt
    • ……

3、遍历数据:v-for

  • 语法:

    v-for="item in items"
    v-for="(item, index) in items" :key="index"
    v-for="(val, key, index) in users" :key="index"
  • 同时使用:key可以增加效率。

  • 案例:

    <!DOCTYPE html>
    <html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <!--Vue对象的HTML模板-->
    <div id="app">
        <ul v-for="item in arr">
            <li v-text="item"></li>
        </ul>
        <ul v-for="(item, index) in arr" :key="index">
            <li>{{index}}-{{item}}</li>
        </ul>
    </div>
    </body>
    <script src="node_modules/vue/dist/vue.js"></script>
    <script>
        // 初始化一个Vue实例
        const app = new Vue({
            el: "#app",  // element缩写,"#app"选择器
            data: {  // 定义数据模型
                arr: [1, 2, 3, 4, 5, 6, 7, 8,]
            }
        });
    </script>
    </html>

4、条件渲染:v-ifv-show

  • v-if:当布尔表达式的值为true时,显示该元素。值为false时,不渲染该元素,效率更高。

  • 可以与v-else-ifv-else联用。

    v-if="布尔表达式"
  • v-show:当布尔表达式的值为true时,显示该元素。始终渲染,当值为false时,设置为display:none,效率更低。

    v-show="布尔表达式"

5、属性绑定:v-bind:

  • 绑定属性(主要用于绑定class属性)。
    <template>
    <div>
      <div class="mydiv" :class="{red: isRed}"></div>
      <p><button type="button" @click="changeBtn">改变颜***utton></p>
      <div class="mydiv" :class="myColor"></div>
      <p>颜色:</p>
      <p>红色<input type="radio" v-model="myColor" value="red" name="myColor"></p>
      <p>蓝色<input type="radio" v-model="myColor" value="blue" name="myColor"></p>
      <p>黑色<input type="radio" v-model="myColor" value="black" name="myColor"></p>
    </div>
    </template>
    <script>
    export default {
    name: 'HelloWorld',
    data () {
      return {
        isRed: false,
        myColor: ''
      }
    },
    methods: {
      changeBtn() {
        this.isRed = !this.isRed;
      }
    }
    }
    </script>
    <style scoped>
    .mydiv {
      width: 500px;
      height: 500px;
    }
    .red {
      background-color: red;
    }
    .blue {
      background-color: blue;
    }
    .black {
      background-color: black;
    }
    </style>

6、计算属性:computed

  • computed:里定义方法,方法必须要有返回值。像普通数据一样使用,不用加()。

  • 计算属性基于它们的依赖进行缓存,只有在它的相关依赖发生改变时才会重新求值。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <!--Vue对象的HTML模板-->
    <div id="app">
        <p>{{birth}}</p>
    </div>
    </body>
    <script src="node_modules/vue/dist/vue.js"></script>
    <script>
        // 初始化一个Vue实例
        const app = new Vue({
            el: "#app",  // element缩写,"#app"选择器
            data: {  // 定义数据模型
                birthday: 14564687945121,
            },
            computed: {  // 计算属性
                birth() {
                    var date = new Date(this.birthday);
                    return date;
                }
            }
        });
    </script>
    </html>

7、监听:watch

  • watch:里定义方法,方法名必须与被监听的数据名一致。

  • 通常在方法里发送异步请求,根据监听的数据值的变化进行即时查询。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <!--Vue对象的HTML模板-->
    <div id="app">
        <input type="text" v-model="search">
    </div>
    </body>
    <script src="node_modules/vue/dist/vue.js"></script>
    <script>
        // 初始化一个Vue实例
        const app = new Vue({
            el: "#app",  // element缩写,"#app"选择器
            data: {  // 定义数据模型
                search: ""
            },
            watch: {    // 监听
                search (newVal, oldVal) { // 方法名与监听的数据名必须一致
                    // 发送异步请求,根据监听的值进行查询
                    console.log(newVal + " " + oldVal);
                }
            }
        });
    </script>
    </html>

3.4 组件化

  • 在大型应用开发的时候,页面可以划分成很多部分。往往不同的页面,会有相同的部分。
  • 如果每个页面都独自开发,会增加开发的成本。所以,将页面的不同部分拆分成独立的组件,在不同的页面***享这些组件,可以避免重复开发。
  • 在Vue里,所有Vue实例都是组件。

1、全局组件:Vue.component()

  • 组件的data必须是函数,保证了复用。

  • 可以在任何实例中使用。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <div id="app">
            <counter></counter>
            <counter></counter>
            <counter></counter>
        </div>
    </body>
    <script src="node_modules/vue/dist/vue.js"></script>
    <script>
        Vue.component("counter", {
            template: "<button @click='num++'>num++:{{num}}</button>",
            data() {
                return {
                    num: 0
                }
            }
        })
        const app = new Vue({
            el: "#app",
        })
    </script>
    </html>

2、局部组件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <div id="app">
            <myhello></myhello>
        </div>
    </body>
    <script src="node_modules/vue/dist/vue.js"></script>
    <script>
        const hello = {
            template: "<div>{{name}}</div>",
            data() {
                return {
                    name: "Xianhuii"
                }
            }
        };
        const app = new Vue({
            el: "#app",
            components: {
                myhello: hello
            }
        })
    </script>
    </html>

3、父向子传递数据:props

  • 父组件使用子组件时,使用自定义属性传递数据:

    • 属性名任意,为子组件的数据名。
    • 属性值为父组件的数据名。
  • 子组件使用props,通过自定义属性的属性名(即子组件的数据名),接收父组件的数据。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div id="app">
        <counter :number="num"></counter>
    </div>
    </body>
    <script src="node_modules/vue/dist/vue.js"></script>
    <script>
        Vue.component("counter", {
            template: "<button @click='number++'>num++:{{number}}</button>",
            props: ["number"]
        })
        const app = new Vue({
            el: "#app",
            data: {
                num: 0
            }
        })
    </script>
    </html>

4、子向父传递数据:$emit()

  • 父:

    <template>
    <div>
      <Sub @paramFun="supFun($event)"></Sub>
      {{num}}
      {{supMsg}}
    </div>
    </template>
    <script>
    export default {
      name: 'Sup',
      data() {
        return {
          num: 0,
          supMsg: ''
        }
      },
      methods: {
        supFun(value) {
          this.num++;
          this.supMsg = value
        }
      }
    }
    </script>
  • 子:

    <template>
    <div>
      <button @click='subFun()'>num++</button>
    </div>
    </template>
    <script>
    export default {
      name: "Sub",
      data() {
        return {
          subMsg: 'subMsg'
        }
      },
      methods: {
        subFun() {
          this.$emit("paramFun", this.subMsg);
        }
      }
    }
    </script>

5、全局注册

  • 在main.js中:
    import Header from './components/Header'
    import Content from './components/Content'
    Vue.component('myheader',Header)
    Vue.component('mycontent',Content)

6、局部注册

  • 在特定Example.vue中:

    <script>
    import Header from './Header'
    import Content from './Content'
    
    export default {
    name: 'HelloWorld',
    components: {
      'myheader': Header,
      'mycontent': Content
    }
    }
    </script>

3.5 路由:vue-router

1、安装

  • 在项目目录下,使用以下命令:

    npm install vue-router --save
  • 安装成功后,在node_modules目录下会新增vue-router模块:

图片说明

2、引入

  • 在引入Vue之后引入:
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script src="../node_modules/vue-router/dist/vue-router.js"></script>

3、使用

    <script>
        const router = new VueRouter({
            routes: [
                {
                    path: "/login", // 路由路径,必须以“/”开头
                    component: loginForm    // 对应的组件
                },
                {
                    path: "/register",
                    component: registerForm
                }
            ]
        })
        const app = new Vue({
            el: "#app",
            router  // 注册router
        })
    </script>

4、案例

  • 组件1:login.js

    // 组件内的template只能有一个跟标签
    const loginForm = {
        template: `
            <div>
                <h1>登录页</h1>
                <p>用户名:<input type="text"></p>
                <p>密&emsp;码:<input type="password"></p>
                <p><input type="submit" value="登录"></p>
            </div>
        `
    }
  • 组件2:register.js

    // 组件内的template只能有一个跟标签
    const registerForm = {
        template: `
            <div>
                <h1>注册页</h1>
                <p>用&ensp;户&ensp;名:<input type="text"></p>
                <p>密&emsp;&emsp;码:<input type="password"></p>
                <p>确认密码:<input type="password"></p>
                <p><input type="submit" value="注册"></p>
            </div>
        `
    }
  • 主页面:index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <div id="app">
            <span><router-link to="/login">登录</router-link></span>
            <span><router-link to="/register">注册</router-link></span>
            <hr>
            <router-view></router-view>
        </div>
    </body>
    <!--引入vue-->
    <script src="../node_modules/vue/dist/vue.js"></script>
    <!--引入vue-router-->
    <script src="../node_modules/vue-router/dist/vue-router.js"></script>
    <!--引入login组件-->
    <script src="js/login.js"></script>
    <!--引入register组件-->
    <script src="js/register.js"></script>
    <script>
        const router = new VueRouter({
            routes: [
                {
                    path: "/login", // 路由路径,必须以“/”开头
                    component: loginForm    // 对应的组件
                },
                {
                    path: "/register",
                    component: registerForm
                }
            ]
        })
        const app = new Vue({
            el: "#app",
            router  // 注册router
        })
    </script>
    </html>

3.6 axios

1、添加axios

  • 项目根目录下,在命令行中输入:

    vue add axios
  • 在Vue项目中的plugins目录下新增axios.js插件:

图片说明

2、使用axios

  • 在Example.vue中的<script>标签的函数中可以直接使用axios调用方法,如下可以将从后端得到的数据赋值给books数组:

    <script>
        export default {
            name: "Example",
            data() {
                return {
                    books: []
                }
            },
            created() {
                const _this = this
                axios.get('http://localhost:8181/book/findAll')
                                     .then(function(resp) {
                    _this.books = resp.data
                })
            }
        }
    </script>
  • GET请求:

    const axios = require('axios');
    
    // Make a request for a user with a given ID
    axios.get('/user?ID=12345')
      .then(function (response) {
        // handle success
        console.log(response);
      })
      .catch(function (error) {
        // handle error
        console.log(error);
      })
      .then(function () {
        // always executed
      });
    
    // Optionally the request above could also be done as
    axios.get('/user', {
        params: {
          ID: 12345
        }
      })
      .then(function (response) {
        console.log(response);
      })
      .catch(function (error) {
        console.log(error);
      })
      .then(function () {
        // always executed
      });  
    
    // Want to use async/await? Add the `async` keyword to your outer function/method.
    async function getUser() {
      try {
        const response = await axios.get('/user?ID=12345');
        console.log(response);
      } catch (error) {
        console.error(error);
      }
    }
  • POST请求:

    axios.post('/user', {
        firstName: 'Fred',
        lastName: 'Flintstone'
      })
      .then(function (response) {
        console.log(response);
      })
      .catch(function (error) {
        console.log(error);
      });

4 项目

4.1 项目技巧

1、安装package.json中的依赖

    npm install

2、运行

    npm run dev
    # 或者
    npm start

4.2 Vue UI框架

4.3 域名

1、域名解析相关概念

  • 本地hosts文件

    ip   域名
  • DNS服务器

    ip   域名

2、本地修改域名

  • SwitchHosts修改IP地址

图片说明

  • 在项目的build/webpack.dev.conf.js中:
    devServer: {
        disableHostCheck:true  // 添加
      }

4.4 Ngnix

1、Ngnix简介

  • Ngnix是一个高性能的Web服务器和反向代理服务器。
  • 更多的时候,我们把Ngnix作为网关,因为它具备网关必备的功能:
    • 反向代理。
    • 负载均衡。
    • 动态路由。
    • 请求过滤。

2、Web服务器

  • Web服务器:Apache服务器、Ngnix、IIS。
  • Web应用服务器:tomcat、resin、jetty。
  • Web服务器只能处理JS、CSS、HTML等静态资源,不能解析JSP等页面。
  • Web服务器的并发能力远高于Web应用服务器。

3、代理

  • 代理(代理客户端):通过客户机的配置,实现让一台服务器代理客户机,客户的所有请求都交给代理服务器处理。
  • 反向代理(代理服务器):用一台服务器,代理真实服务器,用户访问时,不再是访问真实服务器,而是代理服务器。

4、安装目录

图片说明

5、启动、重新加载

  • 启动:

    start ngnix
  • 重新加载:

    nginx -s reload

6、配置:nginx.conf

    worker_processes  1;
    events {
        worker_connections  1024;
    }
    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
        server {
            listen       80;  # 监听端口
            server_name  manage.leyou.com;  # 监听域名
            location / {  # 代理路径
                proxy_pass http://127.0.0.1:9001;
                proxy_connect_timeout 600;
                proxy_read_timeout 60;
            }
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
        }
    }

7、访问解析过程

  • 访问:http://manage.leyou.com
  • hosts文件中找到对应IP地址:manage.leyou.com127.0.0.1
  • 默认端口为80(即此时Nginx监听的端口),找到Ngnix。
  • Ngnix中对manage.leyou.com配置的代理路径为:http://127.0.0.1:9001,即对应的Web项目(此Web项目正在监听9001端口)。