Vue入门

Vue:前后端分离

构建用户界面的渐进式框架,自底向上逐层应用

soc:关注度分离原则

MVVM:双向数据绑定

Vue入门_第1张图片

第一个Vue程序

官方教程Vue.js (vuejs.org)

理解成是一个不停监听页面的ajax

idea需要安装Vue.js插件

安装 — Vue.js (vuejs.org)

Vue在线cdn

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>

放在head中的JS代码会在页面加载完成之前就读取,

而放在body中的JS代码,会在整个页面加载完成之后读取

DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Titletitle>
head>
<body>
  
  <div id="vue">
    {{message}}
  div>

  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
  <script>
      <!-- ViewModel层 -->
      var vue = new Vue({
        			<!--键值之间 必须有空格,就像yml的语法一样 -->
        			<!--绑定id为vue的元素 -->
              el: "#vue",
              data: {
                  <!-- Model层 -->
                  message: "Hello Vue!"
              }
          })
  script>

body>
html>

基本语法

Vue.js 模板语法 | 菜鸟教程 (runoob.com)

所有的属性写法,全部都是key-value键值对,用yml的语法思想来理解vue

v-bind

属性绑定vue数据指令

v-bind:“message” 相当于{{message}}

<div id="vue">
  <span v-bind:title="message">
    鼠标悬停后,可看到message的信息
  span>
div>

导入链接

DOCTYPE html><html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">

判断


<div id="vue">
  <span v-if="message === 'A'">Aspan>
  <span v-else-if="message === 'B'">Bspan>
  <span v-else>Cspan>
div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
  let vue = new Vue({
    el: "#vue",
    data: {
      message: "D"
    }
  })
script>

循环

<div id="vue">
  
  <li v-for="(item,index) in items">
    {{item}}
  li>
div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
  let vue = new Vue({
    el: "#vue",
    data: {
      items: ["java", "html", "mysql", "redis"]
    }
  })
script>

<li v-for="(item,index) in items">
  {{item}} -- {{index}}
li>

变种

<div id="vue">
  <span v-for="item in items">
    {{item.message}}
  span>
div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
  let vue = new Vue({
    el: "#vue",
    data: {
      items: [
        {message: "java"},
        {message: "html"},
        {message: "mysql"},
        {message: "redis"}
      ]
    }
  })
script>

java--0
html--1
mysql--2
redis--3

v-model双向数据绑定

从此开始,vue.js的引入放入了head中

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>

head>

vue会忽略checked,select的值,只取vue的data中的值

<div id="vue">
  
  <select v-model="items">
    <option disabled>请选择option>
    <option>1option>
    <option>2option>
    <option>3option>
  select>

  <span>选中了{{items}}span>

div>

<script>
  let vue = new Vue({
    el: "#vue",
    data: {
      items: ""
    }
  })
script>

在这里插入图片描述


methods事件

<div id="vue">
  
  <button value="点我一下" v-on:click="test">button>
div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
  let vue = new Vue({
    el: "#vue",
    data: {
      items: ["java", "html", "mysql", "redis"]
    },
    methods: {
      test: function (){
        <!--取值vue data中的items-->
          for (let item in this.$data.items) {
            alert(item)
          }
      }//test
    }//method
  })
script>

computed计算属性

computed把结果缓存成一个值

<div id="vue">
  
  <span>computed:{{getTime}}span>
  <span>methods:{{getTime1()}}span>

div>

<script>
  let vue = new Vue({
    el: "#vue",
    //computed把结果缓存成一个值,全部都能被methods替代
    computed: {
      getTime() {
        return "时间戳" + Date.now();
      }
    },
    //当重名时,默认调用methods
    methods: {
      getTime1: function () {
        return Date.now();
      }
    }

  })
script>

在控制台可以看到,computed是将值缓存到了本地

vue.getTime
'时间戳1652064179289'
  
//不刷新页面,多次运行,结果一样
vue.getTime
'时间戳1652064179289'



vue.getTime1()
1652064259827

//methods会刷新数据
vue.getTime1()
1652064266181

Axios异步通信框架

在线cdn

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

Vue - 生命周期详解 - 简书 (jianshu.com)

info中的格式:可以不写,但不要写错

<div id="vue">
  <span>城市:{{info.address.city}}span>
  <a :href="info.url">网址a>
div>

<script>
  let vue = new Vue({
    el: "#vue",
    //该函数返回组件实例的 data 对象
    data(){
      return {
        info: {
          //数值可以不写,但是格式必须相同
          url: null,
          address: {
            city: null
          }
        }
      }
    },
    //vue数据挂载html模板完成后,做ajax的钩子函数,只会执行一次
    mounted(){
      //get实例:用response.data读取文件中的果断json数据,响应给info属性
      axios.get("data/data.json").then(response=>(this.info = response.data));
    }
  })
script>

前端页面闪烁的问题解决方案


Vue.component组件

Vue入门_第2张图片

props中的属性名不能大写

<div id="vue">
  
  <child v-for="item in items" v-bind:children="item">child>
div>

<script>
  //组件名,组件实体
  Vue.component("child",{
    //传参
    props: ['children'],
    //模板
    /**
     * html标签及其中内容 最后都会变成小写
     * 但是vue区分大小写
     */
    template: "
  • {{children}}
  • "
    }) let vue = new Vue({ el: "#vue", data: { items: ["java","mysql","html"] } })
    script>

    插槽

    <div id="vue">
    
      <child>
        <slot1 slot="slot1" v-for="item in items" :item="item">slot1>
        <slot2 slot="slot2" v-for="(item,index) in items" :index="index">slot2>
      child>
    div>
    
    <script>
      Vue.component("child",{
        template: "
  • \ \ \
  • "
    }) //插槽1接收item数据 Vue.component("slot1",{ props: ['item'], template: "元素:{{item}}---" }) //插槽2接收index数据 Vue.component("slot2",{ props: ['index'], template: "索引:{{index}}" }) let vue = new Vue({ el: "#vue", data: { items: ["java","mysql","html"] } })
    script>

    事件分发

    实现功能:插槽中有个按纽,可以删除元素,但是删除的却是Vue实例中的对象元素

    根据双向绑定原则,用前端来中介Vue实例和组件间互相调用

    vue.js中this.$emit的理解

    Vue入门_第3张图片

    <div id="vue">
    
      
      
      <father v-on:test="removeItem(index)">
    
        <child slot="child" v-for="(item,index) in items" :index="index">child>
      father>
    div>
    
    <script>
    
      Vue.component("father",{
        //@click:绑定vue的点击单击监听
        template: "
    \ \ \
    \ "
    , methods: { remove: function (index){ /** 把remove事件分发下去,传递参数index 当remove执行时,子级就会告知父级:触发自定义事件test,也就是Vue实例中的removeItem事件 */ this.$emit("test",index); } } }) Vue.component("child",{ props: ['index'], template: "{{index}}" }); let vue = new Vue({ el: "#vue", data: { items: ["java","mysql","html"] }, methods: { removeItem: function (index){ //从index位开始删除,一次删除一位 //可以增,删,改 this.$data.items.splice(index,1); } } })
    script>

    splice使用https://blog.csdn.net/qq_44921114/article/details/108608851


    Vue-cli(脚手架)

    node.js 理解成maven

    使用阿里定制的cnpm命令行工具代替默认的npm,输入以下代码

    安装成功之后,以后安装依赖包的方式和npm的是一样的,只是npm的命令换成是cnpm就可以了。

     npm install -g cnpm --registry=https://registry.npm.taobao.org
    

    检查是否安装成功:

     $ cnpm -v
    

    C:\Users\林木\AppData\Roaming\npm 包存放路径

    出错了话,node.js会告诉怎么解决,直接执行他告诉你的代码就行

    Vue入门_第4张图片

    vue list查看可以用的包

    安装vue-cli

    第一个vue-cli程序

    npm ERR! enoent ENOENT: no such file or directory, open ‘D:\package.json‘


    Webpack静态模块打包器

    异步加载模块,可以并行加载多个模块

    理解成:把es6规范的前端项目,打包成es5规范

    VUE-CLI Webpack安装使用

    Vue入门_第5张图片

    第一个webpack程序

    新建一个只有.idea的空项目

    hello.js相当于java自定义类

    //暴露一个sayHi方法给外界
    exports.sayHi = function () {
        //到时会在页面上写字
        document.write("

    Hello webpack!

    "
    ); }

    main.js程序主入口

    //在当前目录下引入hello.js
    var hello = require("./hello");
    hello.sayHi();
    

    webpack.config.js:主配置文件,webpack4.0后文件名要是webpack.config.js

    //把模块导出去
    module.exports = {
        //入口:从哪里读取
        entry: "./modules/main.js",
        //输出到哪里
        output: {
            filename: "./js/bundle.js"
        }
    }
    

    控制台运行 webpack 打包,然后会自动生成一个dist目录

    Vue入门_第6张图片

    测试页面引入生成的js文件,就是相当于引入hello.js

    <script src="dist/js/bundle.js">script>
    

    webpack : 无法加载文件 D:\nodejs\node_global\webpack.ps1,因为在此系统上禁止运行脚本

    ERROR in Entry module not found: Error: Can’t resolve ‘./src’ in XXX的一个解决方案

    webpack --watch热部署


    Vue-router

    理解成**@RequestMapping**

    VueRouter路由安装使用

    安装vue-router,保存到dev环境下,也就是config目录下

    cnpm install vue-router --save-dev

    在一个vue项目下

    自定义组件

    Content.vue

    <template>
    <h1>Hello Vue-Router!This is my first VueContent.h1>
    template>
    
    <script>
    //导出一个组件,名叫Content,也相当于命名当前组件为Content
    export default {
      name: "Content"
    }
    script>
    
    
    <style scoped>
    
    style>
    

    Main.vue

    <template>
      <h1>Hello Vue-Router!h1>
    template>
    
    <script>
    export default {
      name: "Main"
    }
    script>
    
    <style scoped>
    
    style>
    

    官方习惯把各种配置文件都叫index.js

    router目录下的index.js

    //导入文件和模块(从node_modules中导入),名字随意
    import Vue from "vue"
    import VueRouter from "vue-router"
    import Main from "../components/Main"
    import Content from "../components/Content";
    
    //上面的Vue实例安装路由(添加插件)
    Vue.use(VueRouter)
    
    //将路由实例化并导出
    export default new VueRouter({
      routes: [
        {
          //地址栏输入路径后,将跳转到Content组件
          path: "/content",
          name: "Content",
          component: Content
        },
        {
          path: "/main",
          component: Main
        }
      ]
    })
    

    main.js Vue项目的主配置文件

    // 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'
    
    //自动扫描目录下的index.js文件
    import router from './router/index'
    
    Vue.config.productionTip = false
    
    /* eslint-disable no-new */
    new Vue({
      el: '#app',
    
      //使用路由,也相当于导入所有路由
      router,
      components: { App },
      template: ''
    })
    

    App.vue 项目的主界面

    <template>
      <div id="app">
    
        
        
        <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>
    

    npm run dev 运行打包项目

    VueRouter报错:Uncaught TypeError: Object(…) is not a function


    整合ElementUI

    Vue入门_第7张图片

    //安装element-ui
    cnpm i element-ui -S
    
    //安装依赖
    cnpm install
    
    //安装SASS加载器( 强化 CSS 的辅助工具 ,强化CSS功能)
    cnpm install sass-loader node-sass --save-dev
    
    npm run dev
    

    去element-ui官网,复制他们的代码

    ElementLogin.vue(自定义登录组件)

    <template>
      <div>
        <el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box">
          <h3 class="login-title">欢迎登录h3>
          <el-form-item label="账号" prop="username">
            <el-input type="text" placeholder="请输入账号" v-model="form.username"/>
          el-form-item>
          <el-form-item label="密码" prop="password">
            <el-input type="password" placeholder="请输入密码" v-model="form.password"/>
          el-form-item>
          <el-form-item>
            <el-button type="primary" v-on:click="onSubmit('loginForm')">登录el-button>
          el-form-item>
        el-form>
    
        <el-dialog
            title="温馨提示"
            :visible.sync="dialogVisible"
            width="30%"
            :before-close="handleClose">
          <span>请输入账号和密码span>
          <span slot="footer" class="dialog-footer">
            <el-button type="primary" @click="dialogVisible = false">确 定el-button>
          span>
        el-dialog>
      div>
    template>
    
    <script>
    export default {
      name: "Login",
      data() {
        return {
          form: {
            username: '',
            password: ''
          },
    
          // 表单验证,需要在 el-form-item 元素中增加 prop 属性
          rules: {
            username: [
              {required: true, message: '账号不可为空', trigger: 'blur'}
            ],
            password: [
              {required: true, message: '密码不可为空', trigger: 'blur'}
            ]
          },
    
          // 对话框显示和隐藏
          dialogVisible: false
        }
      },
      methods: {
        onSubmit(formName) {
          // 为表单绑定验证功能
          this.$refs[formName].validate((valid) => {
            if (valid) {
              // 使用 vue-router 路由到指定页面,该方式称之为编程式导航
              this.$router.push("/main");
            } else {
              this.dialogVisible = true;
              return false;
            }
          });
        }
      }
    }
    script>
    
    <style lang="scss" scoped>
    .login-box {
      border: 1px solid #DCDFE6;
      width: 350px;
      margin: 180px auto;
      padding: 35px 35px 15px 35px;
      border-radius: 5px;
      -webkit-border-radius: 5px;
      -moz-border-radius: 5px;
      box-shadow: 0 0 25px #909399;
    }
    
    .login-title {
      text-align: center;
      margin: 0 auto 40px auto;
      color: #303133;
    }
    style>
    

    配置router

    //导入element-ui模块,和css文件
    import Element from 'element-ui'
    import 'element-ui/lib/theme-chalk/index.css'
    
    import ElementLogin from "../components/ElementLogin";
    
    Vue.use(Element);
    
    export default new VueRouter({
        routes: [
            {
                path: "/login",
                component: ElementLogin
            }
        ]
    })
    

    main.js改变App.vue的生成方式为适配Element

    new Vue({
      el: '#app',
    
      router,
      //ES6的写法,就是生成一个叫App的节点,挂载到根节点上.
      //https://www.jianshu.com/p/0ea899e233a9
      render: h => h(App)
    
    })
    

    App.vue使用组件

    <template>
      <div id="app">
        <router-link to="/login">登录router-link>
    
        <router-view>router-view>
    
      div>
    
    template>
    

    运行发布npm run dev

    报错解决

    Module build failed: TypeError: this.getOptions is not a function 安装node-Sass报错

    或者官方会告诉你用哪个版本Module build failed: Error: Node Sass version 7.0.1 is incompatible with ^4.0.0.

    cnpm install [email protected] --save-dev

    自动生成网站,文档 文档化 (docsify.js.org)


    路由嵌套

    就是在将一个组件 放到 另一个组件下

    index.js

    export default new VueRouter({
      routes: [
        {
          path: "/main",
          component: Main,
    
          //路由嵌套,最后访问/login时,必须是在/main下
          children: [
            {
              path: "/login",
              component: ElementLogin
            }
          ]
        }
    })
    

    main.vue

    <template>
      
      <div>
        <h1>Hello Vue-Router!h1>
    
        <router-link to="/login">登录router-link>
        <router-view>router-view>
      div>
    template>
    

    参数传递及重定向

    取值时,所有的元素必须被标签包裹

    App.vue

    
    <router-link :to="{name:'login',params:{id:1}}">登录router-link>
    

    路由index.js

    routes: [{
        //访问路径时必须携带有id的参数
        path: "/login/:id",
        name: "login",    
        component: ElementLogin
      }
    ]
    

    直接接收参数

    <h1>{{$route.params.id}}h1>
    

    props父子传参

    index.js

    name: "login",
    //允许传递参数
    //当 props 设置为 true 时,route.params 将被设置为组件的 props。
    props: true,
    

    在被跳转页面中用props接收对应的参数,可直接使用

    <h1>{{id}}h1>
    
    export default {
      name: "Login",
      props: ['id'],
    

    push传递表单参数

    登录页面在导出中携带页面表单中的参数

    export default {
      name: "Login",
      data() {
        return {
          form: {
            username: '',
            password: ''
          },
    
          // 表单验证,需要在 el-form-item 元素中增加 prop 属性
          rules: {
            username: [
              {required: true, message: '账号不可为空', trigger: 'blur'}
            ],
            password: [
              {required: true, message: '密码不可为空', trigger: 'blur'}
            ]
          },
    
          // 对话框显示和隐藏
          dialogVisible: false
        }
      },
      methods: {
        onSubmit(formName) {
          // 为表单绑定验证功能
          this.$refs[formName].validate((valid) => {
            if (valid) {
              // 使用 vue-router 路由到指定页面,该方式称之为编程式导航
              //到达指定页面时携带参数
              this.$router.push("/main/"+this.form.username);
            } else {
              this.dialogVisible = true;
              return false;
            }
          });
        }
      }
    }
    

    index.js路由中配置参数列表

    path: "/main/:name",
    props: true,
    component: Main
    

    使用

    <template>
      <div>
        <h1>{{name}}</h1>
      </div>
    </template>
    
    <script>
    export default {
      name: "Main",
      props: ['name']
    }
    </script>
    

    重定向

    routes: [{
        path: "/element",
        component: ElementLogin
      }, {
        path: "/login",
        name: "login",
        props: true,
        //重定向
        redirect: "/element"
      }
    ]
    

    全局路由和路由钩子

    全局路由404

    //当在所有path中都不能匹配时,跳转
    path: "/*",
    component: Main
    

    路由模式

    hash:路径带#符号

    history:路径不带#符号

    路由的index.js

    export default new VueRouter({
        mode: "history",
        routes: [
    

    钩子函数及axios

    vue-axios|axios中文网 | axios (axios-js.com)

    测试目录一般叫mock,放在static目录下

    安装axios模块:cnpm install axios,cnpm install vue-axios

    导入axios模块

    import Axios from "axios"
    import VueAxios from "vue-axios"
    
    //必须先绑定VueAxios,再是Axios
    Vue.use(VueAxios,Axios)
    
    export default {
      name: "Main",
      beforeRouteEnter: (to, from, next)=>{
        console.log("进入路由之前");
    
        //vm实现调用methods中的方法后再放行
        next(vm => {
          vm.getData();
        });
      },
      beforeRouteLeave: (to, from, next)=>{
        console.log("进入路由之后");
        next();
      },
      methods: {
        getData: function (){
    
          //get方式请求文件
          this.axios({
            method: "get",
            url: "../../../static/mock/data.json"
          }).then(function (response){
            //会请求到的数据封装到response中
            console.log(response);
          })
        }
    
      }
    
    }
    

    Vue入门_第8张图片

    你可能感兴趣的:(前端,vue.js,javascript,前端,前端框架)