目录
安装vue工具vue cli
vue cli是vue.js的开发标准工具,vue cli是一个基于vue.js进行快速开发的完整系统
全局安装vue cli:npm install -g @vue/cli
验证安装是否成功:vue -V
创建一个项目
npx vue create vue-demo
注意:项目名无论如何都不能出现大写,必须全小写,但是可以用-来链接多个单词
注意:
我们如图选中即可,注意关闭linter/formatter校检
我们选择版本3
询问配置文件的存放位置,我们选择第一个
是否保存预设,我选n
用什么包管理-npm因为使得熟
成功哩
运行项目
进入local:后面的地址(其实哪个都行)
Vue单文件组件(又名.vue文件,缩写为SFC)是一种特殊的文件格式,他允许将Vue组建的模板、逻辑与样式封装在单个文件中
- <template>
- <h3>我是单文件组件h3>
- template>
- <script>
- export default{
- name:"MyConponent"/* 组件名称 */
- }
- script>
- <style scoped>
- h3{
- background: red;
- }
- style>
scoped属性:该属性表示css标签样式只在当前组件内有效
组件内部元素
加载组件
通常一个应用会以一棵嵌套的组件树的形式来组织
props是可以在组件之上进行传递数据的
- <template>
- <my-component :message="message" :age="age" :names="names">my-component>
- template>
- <script>
- import MyComponent from './components/MyComponent.vue'
- export default {
- name: 'App',
- data() {
- return {
- message:"总有一天,我便超越这个世界",
- age:20,
- names:["lili","makabaka","tangbulibou"]
- }
- },
- components: {
- MyComponent
- }
- }
- script>
- <template>
- <h3>props传递数据h3>
- <p>{{message}}p>
- <p>{{age}}p>
- <ul>
- <li v-for="(item,index) in names" :key="index">{{item}}li>
- ul>
- template>
- <script>
- export default{
- name:"MyConponent",/* 组件名称 */
- props:{
- message:{
- type:String,/* 组件接受的值为string类型 */
- default:""/* 如果不传值则组件默认值为空串 */
- },
- age:{
- type:Number,
- default:0
- },
- names:{
- type:Array,
- /* 数组和对象必须使用函数进行返回 */
- default:function(){
- return []
- }
- }
- }
- }
- script>
理解:两个组件通过v-bind:进行连接,子组件通过props属性对床过来的数据进行接收
自定义事件可以在组件中反向传递,props可以将数据从父组件传递到子组件,那么反向如何操作呢,就可以利用自定义事件实现$emit
- <template>
- <h3>自定义事件的组件交互h3>
- <button @click="sendClickHandle()">点击传递事件button>
- template>
- <script>
- export default{
- name:"MyConponent",/* 组件名称 */
- data() {
- return {
- message:"我变大神,那是必然"
- }
- },
- methods: {
- sendClickHandle(){
- /* 参数1:字符串-事件名称
- 参数2:传递的数据-事件参数 */
- this.$emit("onevent",this.message)/* 自定义事件 */
- }
- },
- }
- script>
- <template>
- <my-component @onevent="getDataHandle">my-component>
- template>
- <script>
- import MyComponent from './components/MyComponent.vue'
- export default {
- name: 'App',
- components: {
- MyComponent
- },
- methods: {
- /* 里面的参数为自定义事件传递数据的参数 */
- getDataHandle(data){
- console.log(data);
- }
- },
- }
- script>
理解:点击事件触发sendClickHandle函数,此函数触发自定义事件onevent并将参数带入父组件,父组件事件已被触发调用带参数的getDataHandle方法来获得数据
每个组件在被创建时都要经过一系列的初始化过程--例如,需要设置数据监听、编译模板、将实例挂载到dom并在数据变化时更新dom等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己代码的机会
- <template>
- <h3>生命周期函数h3>
- <input type="text" v-model.lazy="msg">
- <p>{{msg}}p>
- template>
- <script>
- export default{
- name:"mycomponent",
- data() {
- return {
- msg:""
- }
- },
- beforeCreate() {
- console.log("组件创建之前");
- },
- created() {
- console.log("组件创建之后");
- },
- beforeMount() {
- console.log("组件挂载前");
- },
- mounted() {
- console.log("组件挂载后");
- },
- beforeUpdate() {
- console.log("组件更新前");
- },
- updated() {
- console.log("组件更新后");
- },
- beforeUnmount() {
- console.log("组件卸载前");
- },
- unmounted() {
- console.log("组件卸载后");
- },
- }
- script>
以swiper为例
安装swiper:npm i --save swiper
- <template>
- <div id="a">
- <swiper>
- <swiper-slide class="mySwiper">
- <img src="../assets/test.jpg" alt="图片没了">
- swiper-slide>
- <swiper-slide>
- <img src="../assets/test.jpg" alt="图片没了">
- swiper-slide>
- <swiper-slide>
- <img src="../assets/test.jpg" alt="图片没了">
- swiper-slide>
- swiper>
- div>
- template>
- <script>
- // 引入轮播图组件
- import {Swiper,SwiperSlide} from "swiper/vue"
- import "swiper/css"
- export default{
- name:"mycomponent",
- // 注册组件
- components:{
- Swiper,
- SwiperSlide,
- }
- }
- script>
axios是一个基于promise的网络请求库
安装axios:npm install --save axios
安装querystring:npm install --save querystring
组件中引入:
import axios from axios
import querystring from "querystring"
- <template>
- <div id="a">
- {{msg}}
- div>
- template>
- <script>
- import axios from "axios"
- import querystring from "querystring"
- export default{
- name:"mycomponent",
- data() {
- return {
- msg:""
- }
- },
- mounted() {
- // get请求方式
- axios({
- method:"get",
- url:"https://limestart.cn/"
- }).then(res =>{
- console.log(res.data);
- this.msg=res.data
- })
- // post请求参数
- axios({
- method:"post",
- url:"http://iwenwiki.com/api/blueberrypai/login.php",
- data:querystring.stringify({
- user_id:"iwen@qq.com",
- password:"iwen123",
- verification_code:"crfvw"
- })
- }).then(res=>{
- console.log(res.data);
- })
- },
- }
- script>
注意:data里面的数据必须传递为json格式
- <template>
- <div id="a">
- {{msg}}
- div>
- template>
- <script>
- import axios from "axios"
- import querystring from "querystring"
- export default{
- name:"mycomponent",
- data() {
- return {
- msg:""
- }
- },
- mounted() {
- // get请求方式
- axios.get("https://limestart.cn/")
- .then(res=>{
- console.log(res.data);
- })
- // post请求参数
- axios.post("http://iwenwiki.com/api/blueberrypai/login.php",querystring.stringify({
- user_id:"iwen@qq.com",
- password:"iwen123",
- verification_code:"crfvw"
- })).then(res=>{
- console.log(res.data);
- })
- },
- }
- script>
- import { createApp } from 'vue'
- import App from './App.vue'
- import './registerServiceWorker'
- /* 引入axios */
- import axios from "axios"
- const app=createApp(App)
- /*将axios挂载到全局 */
- app.config.globalProperties.$axios=axios
- // 使用时直接this.$axios()来调用axios
- app.mount('#app')
在日常应用过程中,一个项目中的网络请求会很多,此时一般采用的方案是将网络请求封装起来
封装方案
安装axios:npm install --save axios
安装querystring:npm install --save querystring
组件中引入:
import axios from axios
import querystring from "querystring"
- import axios from "axios"
- import querystring from "querystring"
-
- const errorHandle=(status,info)=>{
- switch(status){
- case 400:
- console.log("语义有误");
- break
- case 401:
- console.log("服务器认证失败");
- break
- case 403:
- console.log("服务器拒绝访问");
- break
- case 404:
- console.log("地址错误");
- break
- case 500:
- console.log("服务器遇到意外");
- break
- case 502:
- console.log("服务器无响应");
- break
- default:
- console.log(info);
- break
- }
- }
- /* 创建自己的网络请求对象 */
- const instance=axios.create({
- /* 网络请求的公共配置 */
- timeout:5000
- })
- //拦截器常用
- //发送数据之前
- instance.interceptors.request.use(
- //拦截成功执行的函数
- //config包含网络请求的所有信息
- config=>{
- if(config.methods==="post"){
- /* 转化post请求参数格式 */
- config.data=querystring.stringify(config.data)
- }
- return config
- },
- //拦截失败执行的函数
- error=>{
- return Promise.reject(error)
- }
- )
- //获取数据之前
- instance.interceptors.response.use(
- //成功时返回结果
- response=>{
- return response.status===200?Promise.resolve(response):Promise.reject(response)
- },
- //失败时返回结果
- error=>{
- const {response}=error
- // 错误处理才是重中之重
- errorHandle(response.status,response.info)
- }
- )
- export default instance
同源策略是浏览器的一项安全策略,浏览器只允许js代码请求和当前所在服务器域名、端口、协议相同的数据接口上的数据,这就是同源策略
理解:当协议、域名、端口号任意一个不相同时,都会产生跨域问题
- <script>
- import axios from "axios"
- export default{
- name:"mycomponent",
- mounted() {
- /* 删掉前面的地址 */
- axios.get("/api/FingerUnion/list.php")//跨域了
- .then(res=>{
- console.log(res.data);
- })
- },
- }
- script>
- //vue.config.js中
- const { defineConfig } = require('@vue/cli-service')
- module.exports = defineConfig({
- transpileDependencies: true,
- /* 解决跨域问题的配置 */
- devServer:{
- proxy:{
- "/api":{
- target:"http://iwenwiki.com",/* 参数为产生跨域的域名地址 */
- changeOrigin:true
- }
- }
- }
- })
注意:解决完跨域之后,要记得重启服务器
在vue中,我们可以通过vue-router路由管理页面之间的关系
vue router是vue.js的官方路由。他与vue.js核心深度集成,让vue.js构建单页面应用轻而易举
在vue中引入路由
安装路由:npm install --save vue-router
配置独立的路由文件
在src文件下新建一个文件夹router里面建一个index.js文件作为路由的配置文件
- // 路由配置文件index.js
- //引入路由,第一个为了创建路由对象,第二个为路由配置需要的一个选项
- import {createRouter,createWebHashHistory} from "vue-router"
- //配置信息中需要页面的相关配置在src文件夹下建一个views文件夹,在文件夹建文件HomeView.vue与AboutView.vue组件
- import HomeView from "../views/HomeView"
- import AboutView from "../views/AboutView"
- //配置路由
- const routes=[
- {path:"/",component:HomeView},
- {path:"/about",component:AboutView}
- ]
- // 创建路由
- const router=createRouter({
- history:createWebHashHistory(),/* 访问方式 */
- /* createWebHistory这种方式需要后台配合1做重定向,否则会出现404问题*/
- routes
- })
- export default router
注意:提前创建好两个组件HomeView.vue与AboutView.vue组件
- // main.js内
- import { createApp } from 'vue'
- import App from './App.vue'
- import './registerServiceWorker'
- // 全局引入路由
- import router from "./router/index.js"
- const app=createApp(App)
- // 使用路由
- app.use(router).mount('#app')
- <template>
- <router-link to="/">首页router-link> |
- <router-link to="/about">关于router-link>
- <router-view>router-view>
- template>
- <script>
- export default {
- name: 'App',
- components: {
-
- }
- }
- script>
路由是管理页面之间的跳转关系的,在跳转的过程中,页面与页面之间也需要传递参数
- const routes=[
- {path:"/",component:HomeView},
- {path:"/about",component:AboutView},
- /* 异步加载方式:如果页面没有被显示出来component后面的代码是不会执行的,不会执行的话就节省了内存空间 */
- {path:"/news",component:()=>import("../views/NewsView.vue")},
- //路由传参
- {path:"/newsdetails/:name",component:()=>import("../views/NewsDetails")}
- ]
在path路径下加:属性名(:属性名就相当于一个路径的占位符)也可以写多个属性
- <template>
- <h3>新闻h3>
- <ul>
- <li><router-link to="/newsdetails/百度">baidu新闻router-link> li>
- <li><router-link to="/newsdetails/网易">网易新闻router-link> li>
- <li><router-link to="/newsdetails/头条">头条新闻router-link> li>
- ul>
- template>
在此文件内要跳转的的路径后加参数,此参数可以传递给上面path路径的name属性
- <template>
- <div>新闻详情div>
- <p>{{$route.params.name}}p>
- template>
通过$route.params.属性来获取传过来的值
- //配置路由
- const routes=[
- {path:"/",component:HomeView},
- { path:"/about",component:()=>import("../views/AboutView.vue"),
- redirect:"/about/us",/* 路由重定向 */
- children:[
- /* 注意:子路由路径前面不带/ */
- {path:"us",component:()=>import("../views/aboutsub/AboutUs")},
- {path:"info",component:()=>import("../views/aboutsub/AboutInfo")}
- ]
- }
- ]
- <template>
- <div class="about">
-
- <router-link to="/about/us">关于我们router-link> |
- <router-link to="/about/info">关于信息router-link>
- <router-view>router-view>
- div>
- template>
vuex是一个专门为vue.js应用程序开发的状态管理模式+库。他采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化
简单来说,状态管理可以理解成:为了更方便的管理组件之间的数据交互,提供了一个集中式的管理方案,任何组件都可以按照指定的方式进行读取和改变数据
使用vuex
安装vuex:npm install --save vuex
在src目录中新建一个store文件夹存放index.js文件
- // index.js内
- import {createStore} from "vuex"
- // vuex的核心作用就是帮我们管理组件之间的状态
- const store=createStore({
- // 通过state对象进行存储
- state:{
- //模拟的数据
- counter:0
- }
- })
- export default store
- import { createApp } from 'vue'
- import App from './App.vue'
- import './registerServiceWorker'
- /* 全局引入vuex */
- import store from "./store"
- const app=createApp(App)
- //将vuex注册
- app.use(store).mount('#app')
- <template>
- <div class="hello">
-
- {{counter}}
- div>
- template>
- <script>
- //引入mapState从vuex
- import { mapState } from 'vuex'
- export default {
- name: 'HelloWorld',
- computed:{
- ...mapState(["counter"])
- }
- }
- script>
- <template>
- <p>{{$store.state.counter}}p>
- template>
常用的核心概念包括:State、Getter、Mulation、Action
作用:对vuex中的数据进行过滤(对读取的方式提供一种更合理的方式)
- import { createStore } from 'vuex'
-
- export default createStore({
- /* 注意state不能更改 */
- state: {
- /* 数据名称随便起 */
- counter:10
- },
- getters: {
- getCounter(state){
- /* counter数据深层的管理 */
- return state.counter>0?state.counter:"counter数据异常"
- }
- },
- })
- <template>
- <div class="hello">
- <h1>HelloWorldh1>
-
- <p>counter={{$store.getters.getCounter}}p>
-
- {{getCounter}}
- div>
- template>
- <script>
- /* 引入mapgetters */
- import { mapGetters } from "vuex";
- export default {
- name: 'HelloWorld',
- computed:{
- ...mapGetters(["getCounter"])
- }
- }
- script>
更改vuex的store中状态的唯一方法是提交mutation。vuex中的mutation非常类似于事件:每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler),这个回调函数就是我们实际进行状态更改的地方,并且他会接收state作为第一个参数
- import { createStore } from 'vuex'
- export default createStore({
- state:{
- counter:10
- },
- /* 更改state状态 */
- mutations: {
- addCounter(state,num){
- state.counter+=num
- }
- /* 注意:任何组件对值得引用都可以得到相应的修改 */
- },
- })
方式一
- <template>
- <div class="hello">
- <h1>HelloWorldh1>
- <p>counter={{$store.getters.getCounter}}p>
-
- <button @click="addClickHandler">增加button>
- div>
- template>
- <script>
- /* 引入mapgetters */
- import { mapGetters } from "vuex";
- export default {
- name: 'HelloWorld',
- methods: {
- /* mutation调用函数 */
- addClickHandler(){
- /* 固定调用方式 */
- this.$store.commit("addCounter",15)
- }
- },
- }
- script>
方式二
- <template>
- <div class="hello">
- <h1>HelloWorldh1>
- <p>counter={{$store.getters.getCounter}}p>
-
- <button @click="addClickHandler">增加button>
- div>
- template>
- <script>
- /* 引入mapMutations */
- import { mapMutations } from "vuex";
- export default {
- name: 'HelloWorld',
- methods: {
- /* mutation调用函数 */
- ...mapMutations(["addCounter"]),
- addClickHandler(){
- this.addCounter(20)
- }
- },
- }
- script>
Action类似于Mutation不同在于
- import { createStore } from 'vuex'
- import axios from "axios"
- export default createStore({
- state:{
- counter:10
- },
- getters:{
- getCounter(state){
- return state.counter>0?state.counter:"counter数据异常"
- }
- },
- /* 更改state状态 */
- mutations: {
- addCounter(state,num){
- state.counter+=num
- }
- /* 注意:任何组件对值得引用都可以得到相应的修改 */
- },
- /* 为异步操作所准备 */
- actions:{
- /* commit就是为了调用mutation里的方法的 */
- asyncAddCounter({commit}){
- axios.get("http://iwenwiki.com/api/generator/list.php")
- .then(res=>{
- commit("addCounter",res.data[0])
- })
- }
- }
- })
- <template>
- <div class="hello">
- <h1>HelloWorldh1>
- <p>counter={{$store.getters.getCounter}}p>
- <button @click="addAsyncClickHandler">异步增加button>
- div>
- template>
- <script>
- export default {
- name: 'HelloWorld',
- methods: {
- addAsyncClickHandler(){
- /* 固定写法,第一种方式 */
- this.$store.dispatch("asyncAddCounter")
- }
- },
- }
- script>
- <template>
- <div class="hello">
- <h1>HelloWorldh1>
- <p>counter={{$store.getters.getCounter}}p>
- <button @click="addAsyncClickHandler">异步增加button>
- div>
- template>
- <script>
- import { mapActions } from "vuex";
- export default {
- name: 'HelloWorld',
- methods: {
- ...mapActions(["asyncAddCounter"]),
- addAsyncClickHandler(){
- /* 第二种方式 */
- this.asyncAddCounter();
- }
- },
- }
- script>
- <template>
- <div class="hello">
- <h1>组合式APIh1>
- <p>{{message}}p>
- <ul>
- <li v-for="(item,index) in names.list" :key='index'>{{item}} li>
- ul>
- <button @click="clickHandle">按钮button>
- div>
- template>
- <script>
- import { ref,reactive } from 'vue'
- export default {
- name: 'HelloWorld',
- /* 组合式API */
- setup(){//类似于data功能
- //ref基本类型使用比较高
- const message=ref("我是个消息")
- //一般用reactive声明对象数组等复杂一点的数据
- const names=reactive({list:["lili","lala","lan"]})
- /* 以前定义在methods里的东西可以定义在setup中了 */
- function clickHandle(){
- message.value="看不见我"
- }
- return{
- message,names,clickHandle
- }
- }
- }
- script>
在2.x中,组件的方法可以通过this获取到当前组件的实例,并执行data变量的修改,方法的调用,组件的通信等等,但在3.x中,setup()在beforeCreate和Created时机就已经调用,无法使用和2.x一样的this,但是可以通过接收setup(props,ctx)的方法,获取当前组件的实例ctx和props
- <template>
- <HelloWorld msg="数据"/>
- template>
- <script>
- import HelloWorld from './components/HelloWorld.vue'
- export default {
- name: 'App',
- components: {
- HelloWorld
- }
- }
- script>
- <template>
- <div class="hello">
- <h1>组合式APIh1>
-
- {{msg}}
- div>
- template>
- <script>
- export default {
- name: 'HelloWorld',
- /* 组合式API */
- /*里面也可以传props */
- props:{
- msg:String
- },
- setup(props,ctx){//类似于data功能
- console.log(this); /* setup中没有this关键字 */
- console.log(ctx); /* setup中ctx就相当于this关键字 */
- console.log(props.msg);
- }
- }
- script>
可以通过生命周期钩子函数前面加"on" 来访问组件的生命周期钩子
- <template>
- <div class="hello">
- <h1>生命周期函数h1>
- div>
- template>
- <script>
- /* 使用生命周期函数时必须引入 */
- import {onMounted} from "vue"
- export default {
- name: 'HelloWorld',
- props:{
- msg:String
- },
- setup(props,ctx){
- /* 没有调用,自动执行,还比以前有优势,以前同一个生命周期函数只能存在一个,现在可以存在多个 */
- onMounted(() => {
- console.log("挂载后");
- })
- onMounted(() => {
- console.log("挂载后的第二个生命周期函数");
- })
- }
- }
- script>
- <template>
- <img alt="Vue logo" src="./assets/logo.png">
- <HelloWorld msg="数据"/>
- template>
- <script>
- import HelloWorld from './components/HelloWorld.vue'
- /* 引入provide */
- import { provide } from 'vue'
- export default {
- name: 'App',
- components: {
- HelloWorld
- },
- setup(){
- /* 传递信息 */
- provide("message","我是消息信息")
- }
- }
- script>
- <template>
- <div class="hello">
- {{val}}
- div>
- template>
- <script>
- /* 引入inject接收消息 */
- import { inject } from 'vue'
- export default {
- name: 'HelloWorld',
- props:{
- msg:String
- },
- setup(){
- const val=inject("message")
- return{
- val
- }
- }
- }
- script>
作用:不再限于模板中只有一个根节点
- <template>
- <div>道生一div>
- <div>一生二div>
- template>