学习VUE第二章组件化编程/第三章使用Vue脚手架

第二章 组件化编程

1.什么是模块什么是组件

模块:
一般就是一个js文件
组件:
它是实现一个应用的局部功能的代码和资源的集合

传统方式编写的话:分为html、css、js
它们的代码复用性不高 、 依赖关系混乱、不好维护

组件:
细分为一个一个的局部的功能,里面包括了代码和资源,提高代码的复用性。

2.组件的基本使用

1.创建组件使用
Vue.extend({}) 注册时传入的对象 和vm中的几乎一样 只是data要写成函数的形式 然后不能写el

2.注册组件
可以在vm中使用components{}注册
注意:
组件的数据要写成函数的形式 ,这样 不会产生连带效果

也可以使用全局注册 Vue.component(‘组件名’,组件)

3.使用就是 用组件名的标签

非单文件组件:
一个文件可以包含多个组件

组件里不可以包含el

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>el   data 的两种写法</title>
    <!-- 1.引入js依赖 -->
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 2.给定一个容器 -->
    <div id="root">
        <!-- 3.使用就是  用组件名的标签 -->
        <person></person>
        <hr/>
        <!-- <school></school> -->
    </div>

    <script type="text/javascript">
        Vue.config.productionTip = false; // 3.关闭生产环境提示
       // 1.创建组件
       const a = Vue.extend({
            template:`
                <div>
                    <h1>我是{{name}}</h1>
                </div>
            `,
            data(){
                return {
                    name:'zhansgan'
                }
            }
        })

       const school= Vue.extend({
            template:`
                <div>
                    <h2>我在{{school}}</h2>
                </div>
            `,
            data(){
                return {
                    school:'湖南'
                }
            }
        })
       
             // 全局注册
        Vue.component('person',person)
        // 4.使用Vue操作这个容器
        new Vue({
            el:'#root',
            //可以在vm中使用components{}注册
            // components:{
            //     person:a
            //     school
            // }
        })


   
    </script>
</body>
</html>

3.组件的几个注意点

1.组件命名的时候
如果有多个单词可以用 - 隔开,但是在注册是时候要用 ’ ’ 引用
也可以使用大驼峰命名法 (但是这个只能在脚手架环境用)

            components:{
                'ce-shi':zijian
            }

2.在命名的时候不要用html已经预留了的标签

3.Vue.extend({}) 可以简写为 {} 的形式 Vue在注册组件的时候还是会调用extend的

4.在定义组件的时候可以使用name来指定组件名在开发者工具的样子

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>el   data 的两种写法</title>
    <!-- 1.引入js依赖 -->
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 2.给定一个容器 -->
    <div id="root">
        <ce-shi></ce-shi>
        <ce></ce>
    </div>

    <script type="text/javascript">
        Vue.config.productionTip = false; // 3.关闭生产环境提示
        
        const zijian=    Vue.extend({
            // name:'xiao',
            template:`
            <div>
                <h1>wishing</h1>
            </div>
            `,
        })

        const obj={
            template:`
            <h1>wo</h1>
            `
        }
        Vue.component('ce',obj)
        
        // 4.使用Vue操作这个容器
        new Vue({
            el:'#root',
            components:{
                'ce-shi':zijian
            }
        })
    </script>
</body>
</html>

4.组件的嵌套

规范,,
vm管理—app组件 在app组件中再往下去管理组件

组件嵌套
是可以在一个组件的创建中去components另一个组件,在template中使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>el   data 的两种写法</title>
    <!-- 1.引入js依赖 -->
    <script type="text/javascript" src="../js/vue.js"></script>
</head>

    <!-- 一般规范
    
    vm管理---app组件   在app组件中再往下去管理组件
    -->
<body>
    <!-- 2.给定一个容器 -->
    <div id="root">
        <!-- <app></app> -->
    </div>

    <script type="text/javascript">
        Vue.config.productionTip = false; // 3.关闭生产环境提示


         // 定义学生组件准备嵌套
    const student = Vue.extend({
        name:'student',
        template:`
        <div>
            <h1>我的名字是{{name}}</h1>
            <h2>w我的年龄是{{age}}</h2>
        </div>
        `,
        data(){
            return {
                name:'张三',
                age:20
            }
        }
    })
    const school=Vue.extend({
        name:'school',
        template:`
        <div>
            <h1>这个学校是{{name}}</h1>
            <h2>地址{{address}}</h2>
            <student></student>
        </div>
        `,
        data(){
            return {
                name:'科技大学',
                address:'长沙'
            }
        },
        //  在这个组件中注册嵌套组件  在模板中使用
        components:{
            student:student
        }

    })


    const pin=Vue.extend({
        template:`
        <div>
            <h1>平级组件</h1>
        </div>
        `
    })
   

    const app = Vue.extend({
        template:`
        <div>
        <school></school>
        <pin></pin>
        </div>
        `,
        components:{
            school,
            pin
        }
    })

        // 4.使用Vue操作这个容器
        new Vue({
            template:`<app/>`,
            el:'#root',
            components:{
                app
            }
        })
    </script>
</body>
</html>

5.VueComponent构造函数

1.首先我们用Vue.extend它返回的就是Vuecomponent的构造函数,它是Vue帮我们生成的.
2.当我们使用<组件标签>的时候,Vue就会帮我们执行new VueComponent(options)的到实例对象

3.组件中组件所管理的函数中的this都是 组件的实例对象

4.每一个Vue.extend({})都会生成一个新的VueComponent

5.VueComponent简称vc

6.vm中的children就是被vm所管理的组件

7.vc和vm是不同的,但是vc中可以复用绝大部分的vm,现在处理vm中的el可以指定为哪个容器服务不能用在vc外

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>el   data 的两种写法</title>
    <!-- 1.引入js依赖 -->
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 2.给定一个容器 -->
    <div id="root">
        <!-- 当我们使用 组件时  Vue就会执行 VueComponent的构造函数 得到vc实例 -->
        <vc></vc>
    </div>

    <script type="text/javascript">
        Vue.config.productionTip = false; // 3.关闭生产环境提示


        //  这个vc  就是我们的Vuecomponent实例对象
        const vc= Vue.extend({
            template:`
            <div>
                <h1>{{name}}</h1>
                <button @click='test'>点我</button>
            </div>
            `,
            data(){
                return {
                    name:'张三'
                }
            },
            methods: {
                test(){
                    // VueComponent中使用this  是指的VueComponent实例对象  (使用普通方法)
                    console.log('名字是',this.name)
                }
            },
        })
        console.log(vc)
        // 4.使用Vue操作这个容器
        new Vue({
            el:'#root',
            components:{
                vc
            }
        })
    </script>
</body>
</html>

6.重要的内置关系

Vue让
vuecomponent的原型对象的原型对象指向了Vue的原型对象

VueComponent.prototype._proto==Vue.prototype

这样可以让vuecomponent实例可以访问到Vue原型上的方法和属性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>el   data 的两种写法</title>
    <!-- 1.引入js依赖 -->
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 2.给定一个容器 -->
    <div id="root">
        <vc></vc>
    </div>

    <script type="text/javascript">
        Vue.config.productionTip = false; // 3.关闭生产环境提示

        Vue.prototype.x=99;   // 把属性放在Vue的原型对象上  vuecomponent实例对象可以访问得到

        const vc=Vue.extend({
            template:`
            <div>
            <h1>{{name}}</h1>
            <button @click='dian'>点我访问</button>
            </div>
            `,
            data(){
                return {
                    name:'zhansgan'
                }
            },
            methods:{
                dian(){
                    alert(this.x)
                }
            }
        })

        console.dir(vc)
        // 4.使用Vue操作这个容器
        new Vue({
            el:'#root',
            components:{
                vc:vc
            }
        })
    </script>
</body>
</html>


        function Dome(){
            this.s=10
        }

       const d= new Dome()

       // Dome.prototype  在函数上的原型  是显示原型对象  我们一般往显示原型对象上加东西
       // d.__proto__   实例上的是   隐式原型对象   
       //  不管是类的原型  还是实例的原型都是同一个   
       console.log(Dome.prototype === d.__proto__)

7.单文件组件

1.一个.vue文件就是一个单文件组件
2.它里面包含了 template(结构)只能有一个根元素、 script(交互数据) style(样式)
3.组件就需要暴露

1.export const zujian  这样就是分别暴露
2.在script 的最下方  用 export  {zujian} 这样就是统一暴露
3.export default zujian  这样就是 默认暴露

引入组件
import 组件名  from  位置
import  {}  from  位置
导入多个  用,隔开
代码组件

需要暴露 以后才可以被引入


<template>
    <div class="demo">
        <h1>学校的名字{{name}}</h1>
        <h2>学校的地址{{addrees}}</h2>
        <button @click="dian">点我弹出学校名</button>
    </div>

</template>

<script>
    export default Vue.extend({
        name:'School',
        data(){
            return {
                name:'东方',
                addrees:'湖南'
            }
        },
        methods: {
            dian(){
                alert(this.name)
            }
        },
    })
</script>

<style>
.demo{
    background-color: yellow;
}
</style>
App 管理所有的组件 在script最上边引入组件
<template>
<div>
    <School></School>
    <Student></Student>
</div>

</template>

<script>
//  1.导入组件到App文件中  由App来管理所有组件
import School from './School.vue'
import Student from './Student.vue'

// 2.在App中注册所有组件
// 3.在模板中使用
 Vue.extend({
    name:'App',
    components:{
        School,
        Student
    }
 })

</script>
main.js创建Vue指定为哪个容器服务,注册app组件
import App from './App.vue'
// 这个是一个入口文件  只要管理App  在这里创建Vue  指明为哪个容器服务
new Vue({
    el:'#root',
    components:{
        App
    }
})
页面 引入js、main.js 使用组件app
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>练习一下 单文件组件</title>
</head>
<body>
    <!-- 2.给定一个容器 -->
    <div id="root">
        <App></App>
    </div>

    <!-- 引入文件在body的最下方去引入  先让模板出来  在去解析 -->
    <script type="text/javascript" src="../../js/vue.js"></script>
    <script type="text/javascript" src="./main.js"></script>
</body>
</html>

第三章使用Vue脚手架

1.初始化脚手架

脚手架是vue cli 命令行接口 ,它是Vue的标准化开发工具

官方文档
文档: https://cli.vuejs.org/zh/。

脚手架的安装

1.如出现下载缓慢请配置 npm 淘宝镜像:npm config set registry
https://registry.npm.taobao.org

2.全局安装@vue/cli。
npm install -g @vue/cli

3.切换到你要创建项目的目录,然后使用命令创建项目
vue create xxxx (这个名字要小写、多个单词用_隔开)

4.启动项目
npm run serve

出现问题安装Vue脚手架版本与node版本不对应
You are using Node v10.14.2, but this version of @vue/cli requires Node ^12.0.0 ||= 14.0.0

解决

1.执行卸载命令删除当前vue-cli: cmd窗口输入:npm uninstall -g @vue/cli
2、执行如下命令安装低版本的: npm install -g @vue/cli@4.5.13 
3、在cmd中执行:vue -V 命令;展示成功。 

2.脚手架文件目录说明 (Vscode开启中断 Ctrl+~)

1…gitignore 忽略文件
2.babel.config.js ES6转化为ES5需要的文件

3.符合npm规范的就会包含
package.json 包的说明书
package-lock.json 包版本控制文件

4.README.md 整个工程进行一个说明描述

5.src
assets(条件资源)放静态资源的
除了App组件 components中放入其他组件
App.vue 管理器它组件的
main.js 服务运行启动的入口
6.public
favicon.ico 网站的页签图标
index.html 页面咯

3.render说明 和Vue完成版和精简版

/* 
	该文件是整个项目的入口文件
*/
//引入Vue   这里引入的是  运行时的vue  没有模板解析器  所以不能解析Vue   
// 当然你也可以引入完整版的Vue  vue/dist/vue.js
import Vue from 'vue'
//引入App组件,它是所有组件的父组件
import App from './App.vue'
//关闭vue的生产提示
Vue.config.productionTip = false

/* 
	关于不同版本的Vue:
	
		1.vue.js与vue.runtime.xxx.js的区别:
				(1).vue.js是完整版的Vue,包含:核心功能+模板解析器。
				(2).vue.runtime.xxx.js是运行版的Vue,只包含:核心功能;没有模板解析器。

		2.因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用
			render函数接收到的createElement函数去指定具体内容。
*/

//创建Vue实例对象---vm
new Vue({
	el:'#app',
	//render函数完成了这个功能:将App组件放入容器中
	render: h => h(App),

	// render:function(createElement){     完整的写法   createElement是一个函数 参数是  标签名内容
	// 	return createElement('h1','你好呀')
	// }

	// render:q=> q('h1','你好啊')

	// template:`<h1>你好啊</h1>`,
	// components:{App},
})

4.修改和查看默认配置

1.Vue的默认配置是隐藏的不会显示的
2.使用
vue inspect > output.js 查看

修改的话得在package.json 包说明文件同包下创建vue.config.js配置文件

去官网查找文档
https://cli.vuejs.org/zh/

module.exports = {
    pages: {
      index: {
        // page 的入口
        entry: 'src/main.js'

      },

    },
    lintOnSave:false  // 关闭语法检查
  }

5.ref属性 给元素或者子组件注册引用信息

<template>
    <div>
        
        <h1 ref="title">欢迎您</h1>
         <school ref="biaoqian"></school>
         <button @click="dian">点我获取标签</button>
    </div>
   <!-- 总结
            ref标签 和id类似  它是Vue提供的指令  
            1.放在标签上 我们可以给元素或者子组件注册引用信息
            2.放在html上面,拿到的就是真实的DOM元素,在组件上拿到的就是组件实例对象(而id在组件上拿到的是组件的所有标签)
            3.通过
                ref='名字' 放在上面
                this.$refs.名字拿取
    -->
</template>
<script>
    import School from './components/School'
    export default {
        name:'app',
        components:{
            School   
        },
        methods: {
            dian(){
                console.log(this.$refs.title)
                console.log(this.$refs.biaoqian)
            }
        },
    }
</script>


6.props配置 组件用来接收参数

    // props这个是用来定义这个组件使用时传递的一些参数
   // props:['age','hoppy']    // 这个是简单定义  它只能接收一个字符串信息  而且 也不能对参数类型限制
//    props:{   // 这个是第二种限制参数的形式  他可以限定参数的类型
//     age:Number,
//     hoppy:String
//    }
props:{
    age:{
        type:Number,  // 限制参数的类型 
        require:false,  // 限制参数是否必须传递
        default:100  // 参数没有传递时的默认值
    },
    hoppy:{
        type:String
    }

注意props的优先级是比data中的数据高的

// Vue不建议修改 传递参数属性  但实际可以改  如果要改建议在data中定一个变量来接收参数  修改data中的
 dataAge:this.age
  this.dataAge++

组件标签传递参数

        <!-- 使用组件时传递参数 -->
         <!-- <school age="20" hoppy="看风景"></school> -->
         <!-- 传递参数的时候可以用v-bind 使得传递参数的时候 是一个表达式执行 -->
         <school :age="20+1" hoppy="看风景"></school>

7.mixin混合 组件重复代码的抽取

当混合与data中的数据或者方法冲突的时候,以自己写的为准,但是当出现多个钩子函数的时候,就都会执行

1.在src下写一个mixin.js混合文件
在这个里面直接写对象 但是要暴露
2.在要用的地方先引入混合mixin
3.在mixins:[]注册混合

mixin.js

// 这个是用来把多个组件中的重复代码抽取出来成为一个对象

export const m={
    methods: {
        dianji(){
            alert(this.name)
        }
    },
}

组件中使用
// 局部引入 这个混合 mixin
import {m} from '../mixin'

export default {
    data(){
        return{
            name:'zhansgan',
            age:20
        }
    },
    // 注册混合  使用['',''] ,多个的话用,隔开
    mixins:[m]
}


在main.js中
// import {m} from './mixin'
// Vue.mixin(m) 
// 引入整个应用都用的混合   全局混合

8.plugin插件 Vue的增强

定义 plugins.js文件

// 插件是Vue的增强,可以在Vue启动前启动插件

// 插件是一个对象的形式,里面写install方法 (第一个参数是Vue,第二个参数是使用的时候传递啥

// 在main.js 创建Vue之前 引入插件 用Vue.use(options)使用插件
export default{
    install(Vue){
        // 在插件中可以定义一些全局过滤器、全局指令、全局混入等
        Vue.filter('jieuq',function(value){
            return value.indexOf(0,4)
        })

        // 自定义指令
        Vue.directive('fbind',{
            bind(e,v){
                e.value = v.value
            },
            inserted(e){
                e.focus()
            },
            update(e,v) {
                e.value = v.value
            },
        })
        // 全局混入
        Vue.mixin({
            data(){
                return {
                    a:'111'
                }
            }
        })
        // Vue原型上的方法 插件都可以使用
        Vue.prototype.hello = ()=>{alert('插件好')}
    }
}

在main.js中使用插件

// 引入插件 
import plugins  from './plugins'
// 使用插件 后面还可以传递参数
Vue.use(plugins)

用插件中的方法

<template>
    <div>
        <!-- 插件过滤器 方法  指令的使用 -->
   <h1>我的名字是{{name | jieuq}}</h1>
  <h1 @click='dian'>我的年龄是{{age}}</h1>
  <input type="text" v-fbind='name'>
    </div>
</template>

9.scoped样式范围

首先每一个组件的style 要是没有写上scoped的话,那么默认是把他们编译在一起的,这样就会有一个重名冲突

会后引入的会覆盖前引入的

在<style scoped 加上的话 他会给用到样式的标签加上一个属性(自动生成) 而在css中会使用[属性名]去控制

style lang=‘css/less’ 默认是css

在App写的样式全局可用 那你就不要写scoped

<style scoped>
/* 在<style scoped 加上的话  他会给用到样式的标签加上一个属性(自动生成) 而在css中会使用[属性名]去控制
    .demo[data-v-22321ebb] {
  background-color: pink;
}
    */
    .demo{
        background-color: pink;
    }
</style>

10.TODO list小案例

在这里插入图片描述

组件化编码流程(通用)

1.实现静态组件:抽取组件,按功能点去拆分,使用组件实现静态页面效果
这里要自己想到怎么分组件 与 命名

2.展示动态数据类型
数据的类型是什么,名称是什么
数据存在哪个组件中:
一个组件再用就放到自身中
多个组件在用就放到多个的父组件中(状态提升)

3.实现交互,绑定事件开始

使用在list存数据的话:
数据是[ {},{}] 的结构
选择框动态选中使用:checked=‘’

<input type="checkbox" :checked="todo.done"/>

参数和传递
使用v-bind才可以使用 表达式啊啊啊

<Myitem v-for="todoobj in todos" :key="todos.id" :todo="todoobj">
 data(){
        return {
            todos:[
                {id:'001',context:'吃饭',done:false},
                {id:'002',context:'睡觉',done:true},
                {id:'003',context:'打游戏',done:false},
            ]
        }
    }
初级组件间通讯

1.App—》子组件 可以通过直接在组件标签中写参数 子组件用props接收

2.子组件往App中传递参数
首先App往子组件传递一个方法 带参数 子组件在需要的地方调用父组件的方法,传递参数 就可以在父组件中使用子组件的参数了

方法也是传递方法名 接收也是用方法名

父组件:
 <Myhead :addTodo="addTodo"></Myhead>
    methods:{
        addTodo(todoobj){
            // 这个方法传递给子组件,参数用子组件来传递
            // 数组使用方法来 使得数据监测成功
            this.todos.unshift(todoobj)
        }

子组件:
 props:['addTodo'],  接收
 this.addTodo(todoobj) 在vc中调用
选择框数据的变换

传递参数可以传递方法

v-model如果是checkbox 那么v-model如果是一个bealoon值的话就是比绑定checked

指定的语法
v-XX:属性名=‘属性值’

v-model为啥操作props了还没有报错 是因为Vue值监控了对象一层,没有监视对象内部属性的变换
props传递对象,在props中修改对象内部值,竟然data中的数据也改变了
            <!-- 这种是把数据传递给App,让app去修改data中的数据  而不是修改props -->
            <input type="checkbox" :checked="todo.done" @change="gaibian(todo.id)"/>
            <!-- 这种直接通过 v-model去修改 props的数据了  不推荐用 -->
            <input type="checkbox" v-model="todo.done"/>

App中的

        changedone(id){
            // 去遍历数据得到 具体是哪个todo  把那个todo的done数据该掉
            this.todos.forEach((todo)=>{
                if(todo.id === id){
                    todo.done = !todo.done
                    return;
                }
            })
删除按钮的实现,和底部的统计reduce数组函数

1.li:hover {background}这个是 选中加深颜色

li :hover{
    background-color: darkgray;
}
li:hover button{
    display:block
}

2.点击删除按钮,就把id传递给App组件,让App去过滤删除

        shandelete(id){
            // 用过滤来删除
            this.todos = this.todos.filter((x)=>{
                return x.id !== id
            })

底部统计用数组的 reduce函数
动态计算属性 选中有多少个

    computed:{
        sizeDone(){
            // 数组的统计函数 reduce 它第一个参数是函数  两个参数 一个是统计前一个的值  另一个是数组当前遍历值
            // 数据有多少就会执行多少次 reduce 最后一次执行的返回值就是 reduce的返回值
            // 第二个参数是 初始统计值
          return  this.todos.reduce((pre,cur)=>{
                return pre+(cur.done ? 1 : 0)
            },0);
        }
    }
底部全选按钮的实现 和 清除

1.可以接收用户输入,并且想要有初始化值和改变值 那么可用v-model
不用v-model实现全选按钮:

1.初始化 全选按钮的选中和不选中   就是选中的等不等于全部的
 <input type="checkbox" :checked="allcheck" @change="changecheck">

        todosize(){
          return this.todos.length
        },
        allcheck(){
          // 一个计算属性是可以有另外的计算属性计算得来的
          return this.sizeDone === this.todosize
        }

2.点击全选,要把数据全选或者全取消  通知App修改数据
        changecheckapp(isall){
            this.todos.forEach((x)=>{
              x.done = isall
            })
        }

    methods:{
      changecheck(e){
        this.changecheckapp(e.target.checked)
      }
    }

使用V-model:

1.把v-model绑定为一个  初始就是选中的等不等于全部的值  改变的话,就会使用set方法区修改数据

      <!-- 通过双向绑定一个计算属性  在计算属性中 使用 get set方法的话就要去修改app中的数据 -->
          <input type="checkbox" v-model="allcheck">

        allcheck:{
          // 一个计算属性是可以有另外的计算属性计算得来的
          get(){
            return this.sizeDone === this.todosize
          },
          set(value){
            this.changecheckapp(value)
          }
        }

清除选中,用过滤

      cleartodos(){
        // 点击这个直接让app去过滤选中的按钮就可以
        this.clearto()
      }

app中:
        clearto(){
         this.todos= this.todos.filter((x)=>{
            return !x.done
          })
        }
修改按钮的实现todo.hasOwnProperty(‘isedit’) 判断一个对象内是否有这个属性

1.需要增加一个修改按钮,并且控制一下修改按钮的显示

            <!-- <input type="checkbox" v-model="todo.done"/> -->
            <span v-show="!todo.isedit">{{todo.context}}</span>
            <!-- 增加一个输入框 -->
            <input v-show="todo.isedit" type="text" @blur="editDone(todo.id,$event)" :value="todo.context">

  <button v-show="!todo.isedit" class="btn btn-edit" @click="editTitle(todo)">修改</button>

2.需要新增一个输入框,当点击修改时,显示输入框,隐藏span,失去焦点blur的时候,把用户输入的数据放入,在隐藏输入框,显示span

 editTitle(todo){
          // 给这个对象新增一个控制编辑的属性
          if(!todo.hasOwnProperty('isedit')){
            console.log('新增执行了')
            this.$set(todo,'isedit',true)
          }else{
            todo.isedit = true
          }
        },
        editDone(id,e){
          if(!e.target.value.trim()){return alert("输入不能为空")}
          // 修改完成失去焦点 要把用户输入的值 写入数据 并且 把isedit置为false
          this.$bus.$emit('editdata',id,e.target.value)
          this.todo.isedit = false
        }

在vuemounted中去绑定事件    // 修改title
    this.$bus.$on('editdata',(id,value)=>{
        this.todos.forEach((todo)=>{
                if(todo.id === id){
                    todo.context = value
                    return;
                }
            })
    })

11.浏览器本地存储

1.localstorage 本地存储 除非你手动清除 不然一直在

2.sessionstorage 会话存储 打开浏览器就是一次会话 关闭就没有了

四个API:

// cookie key和value都是字符串
           sessionStorage.setItem('msg','我是帅')
           localStorage.getItem('msg')
           sessionStorage.removeItem('msg')
           sessionStorage.clear()
           
JSON.parse
JSON.Stringify

12.利用本地存储保存ToDo案例中的数据

变量 = 值(为null)的话 || 【】就去后面这个值

1.首先要把Todo中的数据初始化为空

   // 这个的意思是前面为真可以用那我就用  没有用那就只能用[]后面的
            todos:JSON.parse(localStorage.getItem("todos")) || []

2.当添加的时候在往浏览器中加入数据

watch:{
      // 监控todos数据 改变 就往浏览器中存  
      // 现在watch没有监测到 对象里面的值的改变  所以要开启深度监视 deep
      todos:{
        deep:true,
        handler(value){
        
          localStorage.setItem("todos",JSON.stringify(value));
      
        }
      }
    }

也就是我们可以启用watch监视来达到效果

13.自定义事件的基本使用 this.$emit(‘事件名’,this.name)

1.首先要给标签绑定自定义事件(两种)

1. v-on:事件名=‘事件函数’
2. 通过ref=‘名字’  在通过this.$refs.名字.$on('事件名',函数)

ref它写在html标签上的话 就是this.$refs.名字取得真实的DOM的元素
写在组件上的话,  就是获取组件实例对象

2.在绑定了事件的组件中,使用this.$emit(‘事件名’,参数)去触发

在接收参数的时候如果后面有多个参数想要一起接收可以使用
…param可以使用这个来接收所有参数,得到一个数组

        <!-- <Student v-on:jin="sendStudentName"></Student> -->
        <!-- 第二种通过ref来绑定 -->
        <Student ref="student"></Student>

事件函数:
            methods:{
                getSchoolName(name){
                    alert(name)
                },
                sendStudentName(name){
                    alert(name)
                }
            },
            mounted(){
                // 挂载完成 就给student加上自定义事件
                this.$refs.student.$on('jin',this.sendStudentName)
            }

事件绑定在谁身上就要由谁触发
    methods:{
        getName(){
            this.$emit('jin',this.name)
        }
    }

这个$方法名一般是在对象上,类上是直接方法名

14.销毁自定义事件(事件在哪个身上由哪个销毁)

通过
this.#off(‘事件名’) 或者[‘’,‘’]数组的形式 或者直接销毁全部不写参数

注意这个组件destroy之后那么这个组件上的watch和这个组件的子组件和自定义事件都会被销毁

让事件只执行一次就是在这个后面加上一个once

<Student v-on:jin="sendStudentName" @test.once="m1"></Student>

15.自定义事件的总结

注意事项:

  1. 在组件标签上要想使用原生事件那么就要在事件后加 .native来说明,不然会被当做一个自定义事件 ,而且这个事件会加载组件的最外层元素上。
     <Student @click.native="add"></Student>
  1. 使用ref来在mounted挂载完成获取组件实例对象来绑定事件的时候,后面的这个回调函数如果写的是普通函数,那么它的this是 谁调用的谁是 要写成箭头函数的话就会往外找
            mounted(){
                // 挂载完成 就给student加上自定义事件
                this.$refs.student.$on('jin',(name)=>{
                    console.log('事件被执行了',name,this)
                })
            }

16.全局事件组件 : 任意组件之间通讯

在这里插入图片描述

全局事件总线是基于这个自定义事件的
实现有两个要求
1.x要全部的组件都可以看见

vc的实例对象都可以访问到Vue原型上的属性和方法
Vueconponent.prototype._proto==Vue.protopyte
所以可以放在Vue的原型上

1在main.js上
// 把数据放在Vue的原型上 ,所有组件实例就都可以访问了
Vue.prototype.x=100

2.器他组建访问
    mounted(){
        console.log("Student",this.x)
    }

因为放在这个Vue原型对象上的傀儡需要访问到$on$emit$off 这些都是原型对象上的动西,所以这个傀儡要是一个 VM或者VC
VC:

在main.js中  
const x = Vue.extend({}) 得到vuecomponent的构造函数
const vc=new x()
Vue.prototype.x = vc  这样就好了

在这里插入图片描述

使用:
在需要用到别人传递来的参数的组件中,通过$on给这个傀儡绑定事件,另外在这个组件被销毁前beforedestroy,要解绑傀儡身上的自定义事件 $off

// 把数据放在Vue的原型上 ,所有组件实例就都可以访问了
// Vue.prototype.x=100

// 定义傀儡
// const x = Vue.extend({})
// const vm = new x()

// Vue.prototype.$bus=vm

// 优化为  直接使用vm
new Vue({
    el:'#app',
    render: h =>h(App),
    // 在只有事件 生命周期刚开始的时候  就给这个Vue绑定
    beforeCreate(){
        Vue.prototype.$bus=this
    }
})

在要用到传递参数的组件上,通过$emit触发这个事件 传递参数

要用到参数的组件上

    mounted(){
        // 组件挂载完成给 傀儡绑定事件
        this.$bus.$on('hello',(name)=>{
            console.log("组件间任意通讯被触发了",name)
        })
    },
    beforeDestroy(){
        // 组件销毁前 解绑自定义事件
        this.$bus.$off('hello')
    }

传递参数的组件上

    methods:{
        sendStudentName(){
            this.$bus.$emit('hello',this.name)
        }
    }

17.消息的订阅与发布:任意组件之间通讯

添加额外的库 pubsub(publish、subscribe).js发布订阅

使用步骤:
1.安装pubsub.js npm install --save pubsub-js
2.引入pubsub-js

import pubsub from 'pubsub-js'

3.在要用到数据的地方 订阅消息 通过pubsub对象.subscribe(消息名,回调函数) 这个回调函数第一个参数是消息名 第二个才是传参
在发消息的地方通过 publish(‘消息名’,参数)去发送消息

发消息
        pubsubAge(){
            // 通过pubsub.js  发送消息
            pubsub.publish('getAge',this.age)
        }

收消息
        // 订阅消息  这个订阅消息会返回一个 消息id 用来撤销消息
      this.pubid =  pubsub.subscribe('getAge',(msgName,age)=>{
            // 要写箭头函数  这里的this才是 vc  不然就是undifand
            console.log('我收到消息了',msgName,age)
        })
        
        // 组件销毁前  撤销订阅消息
        pubsub.unsubscribe(this.pubid)

如果不想用到参数中的某个参数可以用_代替站位

18.Vue实例上的$nextTick

1.他的作用是:
当我们对数据进行修改操作时,我们要对新的DOM元素进行操作的时候,那么我们可以在nextTick上指定回调函数,那么这个函数会在DOM更新完成后调用

语法:
this.$nextTick(回调函数)

          // 获取焦点   这个nexttick 在下一次更新完成DOM元素后被调用
          this.$nextTick(function(){
            this.$refs.editFocus.focus()
          })

19.Vue动画效果(不太了解)

1.transition(过度转变) 包裹住标签动画 transition最终会没有的

首先你要在用
<tansition 去包住标签 可以在这个上面使用name
使用样式去控制标签

<template>
    <div>
        <!-- 用transition 来标注一个标签  他只能包一个根元素的标签  多个的话要transition-group   每一个标签要加:key
        appear属性表示 开始来显现动画 -->
        <transition name="hello" appear>
            <h1 v-show="qie">我的名字是{{name}}</h1>
        </transition>
    
     <button @click="qie = !qie">点我来回切换</button>
    </div>
</template>

<script>
// eslint-disable-next-line no-unused-vars
const a = function(){
    
}

export default {
    name:'Test',
    data(){
        return{
            name:'zhansgan',
            qie: true
        }
    },
}
</script>

<style>
    h1{
        background-color: green;
        /* transform: 1s linear; */
    }
    /* 动画效果的话要配置样式 transition要是没有写name  就会直接用v来控制 全部
    .hello-enter 表示进入的起点 .hello-leave-to离开的终点
     hello-enter-to,  表示进入的终点  
     hello-enter-active  表示进入的过程中
    */
    .hello-enter,.hello-leave-to{
        transform: translateX(-100%);
    }
    .hello-enter-to,.hello-leave{
        transform: translateX(0);
    }
    .hello-enter-active,.hello-leave-active{
        transform: 3s linear;
    }

</style>

20.集成第三方动画

1.使用上npmjs.com这个网站
2.搜索animate.css这个网站

1.安装animate这个动画样式
npm install animate.css --save

2.引入这个样式
import “animate.css”

3.使用api
        <!-- 用transition 来标注一个标签  他只能包一个根元素的标签  多个的话要transition-group
        appear属性表示 开始来显现动画 -->
        <transition name="animate__animated animate__bounce" appear
        enter-active-class="swing"
        leave-active-class="backOutUp"
        >
            <h1 v-show="qie">我的名字是{{name}}</h1>
        </transition>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值