vue-cli笔记

vue的生命周期:

借鉴了react

钩子函数:

change()        挂载完毕,vue完成模板解析,并把初始的真实的dom元素放入到页面后执行

beforeCreate() {
    // 数据代理和数据监测创建之前
    console.log('beforeCreate')
},
created() {
    console.log('created')
},
beforeMount() {
    console.log('beforeMount')
},
mounted() {
    console.log('mounted')
},
beforeUpdate() {
    console.log('beforeUpdate')
},
updated() {
    console.log('updated')
},
beforeDestroy() {
    console.log('beforeDestroy')
},
destroyed() {
    console.log('destroyed')
}

 组件化:

单页面项目

传统的写法:

组件方式: 

 

模块化:

一个大的js文件拆分成很多个文件

 1、创建组件(非单文件组件):

// 创建组件
const school = Vue.extend({
    // 不用写el配置项,因为组件由vm管理
    template: `
      <div>
        <div>{{ school.name }}</div>
        <div>{{ school.address }}</div>
      </div>
    `,
    data() {
        return {
            student: {
                name: 'tom',
                age: '18'
            }
        }
    }
})

超级简写:

const school = {
    template: `
      <div>
          <div>{{ school.name }}</div>
          <div>{{ school.address }}</div>
          <div>
                <button @click="showName">点我</button>
          </div>
      </div>
    `,
    data() {
        return {
            school: {
                name: '尚硅谷',
                address: '北京'
            }
        }
    },
    methods: {
        showName() {
            console.log(this.school.name)
        }
    }
}

 2、注册组件(局部注册):

const vm = new Vue({
    el: '#app',
    components: {
        school: school,
        student: student
    }
})

全局注册组件:

Vue.component('hello',hello)

 3、使用组件:

<div id="app">
    <school></school>
</div>

组件的命名方式:

MySchool        只能在脚手架里用

my-school

组件的嵌套案例:

const school = {
    template: `
      <div>
      <div>{{ school.name }}</div>
      <div>{{ school.address }}</div>
      <div>
        <student></student>
      </div>
      </div>
    `,
    data() {
        return {
            school: {
                name: '尚硅谷',
                address: '北京'
            }
        }
    },
    components: {
        student
    }
}

 

首先要挂载app组件:

new Vue({
    template: `
      <app></app>
    `,
    el: '#app',
    // 注册组件
    components: {
        app
    }
})

 VueComponent:

每一个组件都是一个VueComponent函数,每次调用Vue.extend(),每次都会new一个VueComponent

组件里函数的this是VueComponent,但是它的结构和vm一样,vm是Vue的实例,但是,VueComponent是vm的子组件

VueComponent.prototype.__proto__=Vue.prototype

所以,vc可以访问到vm上的属性和方法

单文件组件:

文件名:ABC.vue

webpack可以把.vue转换成html、css、js。但是我们通常使用vue-cli脚手架

3种暴露方式:

<script>
// 1、分别暴露,导入时需要{}
export const school = Vue.extend({
  data() {
    return {
      school: {
        name: '尚硅谷',
        address: '北京'
      }
    }
  }
})
// 2、统一暴露,导入时需要{}
export {
  school
}
// 3、默认暴露,一般使用
export default school
// 3、的简写
export default {
  name:'School', // 跟文件名保持一致
  data() {
    return {
      school: {
        name: '尚硅谷',
        address: '北京'
      }
    }
  }
}
</script>

单文件组件的案例:

<template>
  <div class="demo">
    <div>{{ student.name }}</div>
    <div>{{ student.age }}</div>
  </div>
</template>

<script>
export default {
  name: 'Student',
  data() {
    return {
      student: {
        name: 'tom',
        age: '18'
      }
    }
  }
}
</script>

<style>
.demo {
  background: red;
}
</style>

App.vue管理所有的组件:

<template>
  <div class="demo">
    <School></School>
    <Student></Student>
  </div>
</template>

<script>
import School from './School'
import Student from './Student'

export default {
  name: 'App',
  components: {
    School,
    Student
  }
}
</script>

<style>
.demo {
  background: red;
}
</style>

因为.vue文件不能new Vue,所以我们还需要写一个main.js:

import App from './App'

new Vue({
    el: '#app',
    template: `<App></App>`,
    components: {App}
})

这时候没有容器,所以我们还需要写我们项目中唯一一个index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--容器-->
<div id="app"></div>
<script src="./js/vue.js"></script>
<!--入口文件-->
<script src="main.js"></script>
</body>
</html>

创建脚手架vue-cli:

 全局安装脚手架:

npm i -g @vue/cli

创建一个vue项目:

vue create vue-demo

vue-cli的结构:

package.json:包管理文件

package-lock.json:包版本控制文件

assets目录:放静态资源

components目录:放所有的组件

public目录:里面有项目的唯一一个index.html文件

npm run build:构建项目,打包项目,所以功能都写完了,最后构建成项目

@/:src目录下

<!--使IE浏览器用最高的渲染级别渲染页面-->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--开启移动端理想视口-->
<meta name="viewport" content="width=device-width,initial-scale=1.0">

<%= BASE_URL %>:public目录下

<%= htmlWebpackPlugin.options.title %>:在package.json里面找网站名,webpack里面的插件完成的功能

<noscript></noscript>:如果浏览器不支持script,那么这个标签里面的内容就会显示

render: h => h(App):创建App元素,因为引入的是esm的js,为了减少体积

.esm.js:采用了es6的模块化的语法的js

vue.config.js:vue-cli的默认配置文件,可以设置关闭语法检查

项目启动,脚手架会运行main.js 

  开发模式启动:

npm run dev

或者生产模式启动:

npm run serve

main.js:

// 该文件是整个项目的入口文件
// 引入Vue
import Vue from 'vue'
// 引入App组件,它是所有组件的父组件
import App from './App.vue'
// 关闭vue的生产提示
Vue.config.productionTip = false

new Vue({
    render: h => h(App),
}).$mount('#app')

ref属性:

<div ref="title">{{ msg }}</div>
<School ref="sch"></School>

console.log(this.$refs.title) // 真实dom元素
console.log(this.$refs.sch) // vc

props:表示从外界接收属性

复用组件时,但是数据不同,数据和方法从外部传入组件内

不建议在内部组件修改传入的值,解决方案:在内部组件再定义一个属性

<Student name="tom" sex="女" age="18"></Student>

第一种方式:

export default {
  name: "Student",
  data() {
    return {}
  },
  // 简单接收
  props: ['name', 'sex', 'age']
}

 第二种方式:

<!--数值类型的age-->
<Student name="tom" sex="女" :age="18"></Student>
props: {
  name: String,
  sex: String,
  age: Number
}

第三种方式:

props: {
  name: {
    type: String,
    required: true
  },
  sex: {
    type: String,
    required: true
  },
  age: {
    type: Number,
    default:18
  }
}

 mixin混合:

导入js文件,使用js文件内的属性,方法,以及统一挂载方法

如果混合与组件有相同属性,混合的属性不导入,挂载的方法会结合

showName.js:

export const showName = {
    methods: {
        showName() {
            console.log(this.name)
        }
    }
}

School.vue:

<div @click="showName">学校名:{{ name }}</div>

data() {
  return {
  }
},
mixins:[showName]

全局的混合:

main.js:

import {showName} from "./showName";
Vue.mixin(showName)

插件:

plugins.js:

export default {
    install(Vue, a, b) {
        console.log(Vue, a, b)
    }
}

main.js:

// 导入插件
import plugins from "./plugins";
// 使用插件
Vue.use(plugins,1,2)

scoped:

让样式只在局部生效,防止冲突

两个模块中的style样式出现类名重复,导致后导入的组件覆盖先导入的组件

解决方案:<style scoped></style>即可解决

localStorage浏览器本地存储:

用例:搜索引擎的搜索历史,浏览器关闭还在

// 保存
localStorage.setItem('user', JSON.stringify(p))
// 读取,如果读不到是null
let user = localStorage.getItem('user')
// 删除
localStorage.removeItem('user')
// 清空
localStorage.clear()

sessionStorage浏览器会话存储:

特点:浏览器关闭会清除

// 保存
sessionStorage.setItem('user', JSON.stringify(p))
// 读取,如果读不到是null
let user = sessionStorage.getItem('user')
// 删除
sessionStorage.removeItem('user')
// 清空
sessionStorage.clear()

自定义事件:

适用于子组件给父组件传值

Student.vue

<div><button @click="sendStudentName">点我</button></div>
methods:{
  sendStudentName(){
    // 自定义事件
    this.$emit('sendStudent',this.name)
  }
}

App.vue:

第一种接收方式:

<Student @sendStudent="getStudentName"></Student>
methods: {
  getStudentName(val,...params) {
    console.log(val,params)
  }
}

第二种接收方式:

mounted() {
  // 挂载后,4秒后绑定了一个事件
  setTimeout(() => {
    this.$refs.student.$on('sendStudent', this.getStudentName)
  }, 4000)
}

解绑事件:

Student.vue:

<button @click="unbind">解绑事件</button>
methods: {
  unbind() {
    this.$off('sendStudent')
  }
}

解绑多个事件:

this.$off(['sendStudent','demo'])

解绑当前组件的全部自定义事件:

this.$off()

全局事件总线:

自定义事件绑定在vm上

使用一个组件来辅助其他组件交互数据,使得其他兄弟组件可以交互数据和方法

main.js:

beforeCreate() {
    // 全局事件总线
    Vue.prototype.$bus = this
}

School.vue:

mounted() {
  this.$bus.$on('hello', (val) => {
    // 绑定事件
    console.log('i am school ', val)
  })
},
beforeDestroy() {
  // 解绑事件
  this.$bus.$off('hello')
}

Student.vue:

  methods:{
    sendStudentName(){
      // 触发事件
      this.$bus.$emit('hello','tom')
    }
  }

消息订阅与发布:

一种组件间通信的方式

我们使用这个库:

npm i pubsub-js@1.6.0

发送方,Student.vue:

// 消息订阅与发布
import pubsub from 'pubsub-js'

export default {
  name: "Student",
  methods: {
    sendStudentName() {
      // 发送消息
      pubsub.publish('hello', 'tom')
    }
  }
}

接收方,School.vue:

import pubsub from 'pubsub-js'

export default {
  name: "School",
  data() {
    return {
      pubId: '',
    }
  },
  methods: {
    hello(msgName, data) {
      console.log('hello 接收消息执行了,消息名:' + msgName + ',数据:' + data)
    }
  },
  mounted() {
    // 接收消息
    this.pubId = pubsub.subscribe('hello', this.hello)
  },
  beforeDestroy() {
    // 解绑事件
    pubsub.unsubscribe(this.pubId)
  }
}

$nextTick        会在dom节点更新之后再执行

// 获取焦点
this.$nextTick(() => {
  this.$refs.inputTitle.focus()
})

动画:

  <button @click="isShow=!isShow">点我</button>
  <!--appear 开局显示-->
  <transition appear name="my">
    <h1 v-show="isShow">hello</h1>
  </transition>

<style>
  @keyframes my_animation {
    from {
      transform: translateX(-100px);
    }
    to {
      transform: translateX(0px);
    }
  }
  
  .my-enter-active {
    animation: my_animation 1s;
  }
  
  .my-leave-active {
    animation: my_animation 1s reverse;
  }
</style>

过渡:

.my-enter,.my-leave-to{
  transform: translateX(-100%);
}

.my-enter-active,.my-leave-active{
  transition: 1s linear;
}

.my-leave-to,.my-enter {
  transform: translateX(0);
}

多个元素的过度:

<transition-group appear name="my">
  <h1 v-show="!isShow" :key="1">hello</h1>
  <h1 v-show="isShow" :key="2">尚硅谷</h1>
</transition-group>

使用第三方动画库:

npm i animate.css
import 'animate.css'

axios:

npm i axios
import axios from 'axios'

解决跨域问题:

同源策略:协议、ip、端口都一致

前端配置代理,方案一:

请求本服务器的地址:

axios.get('http://localhost:8080/student/getStudents/').then(res => {
    console.log('ok')
    console.log(res.data)
}).catch(e => {
    console.log(`请求失败:${e.message}`)
})

本服务器再转发到后台服务器的地址:

const {defineConfig} = require('@vue/cli-service')
module.exports = defineConfig({
    transpileDependencies: true,
    lintOnSave: false, // 关闭eslint校验
    devServer: { // 配置devServer
        // host: 'localhost', // 项目运行的ip
        // port: 80, // 项目运行的端口号
        proxy: 'http://localhost:8081', // 服务器的地址
    },
})

方案二:

devServer: {
    proxy: {
        '/api': { // 匹配所有以/api开头的请求路径
            target: 'http://localhost:8081', // 后端服务器的路径
            changeOrigin: true, // 模拟后端服务器的端口,也就是8081
            pathRewrite: {'^/api': ''}
        },
    }
},

插槽:

默认插槽:

App.vue:

<Category :listData="foods" title="美食">
  <img src="@/assets/logo.png">
</Category>

<Category :listData="games" title="游戏">
  <ul>
    <li v-for="(item,index) in games" :key="index">{{ item }}</li>
  </ul>
</Category>

 Category.vue:

<div class="category">
  <h3>{{ title }}分类</h3>
  <!--定义一个默认插槽-->
  <slot>
    <!--没有给插槽传值的情况的默认值-->
  </slot>
</div>

具名插槽:

<slot name="footer"></slot>
<a href="javascript:" slot="footer">单机游戏</a>

作用域插槽:

子传父形式

语法:

Category.vue:

<template>
  <div class="category">
    <h3>{{ title }}分类</h3>
    <slot :games="games"></slot>
  </div>
</template>

<script>
export default {
  name: "Ctegory",
  props: ['title'],
  data() {
    return {
      games: ['红色警戒', '穿越火线', '劲舞团', '超级玛丽'],
    }
  }
}
</script>

App.vue:

<Category title="游戏">
  <template scope="{games}">
    <ul>
      <li v-for="(item,index) in games" :key="index">{{ item }}</li>
    </ul>
  </template>
</Category>

参考视频:尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通_哔哩哔哩_bilibili

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蒋劲豪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值