导航


HTML

CSS

JavaScript

浏览器 & 网络

版本管理

框架

构建工具

TypeScript

性能优化

软实力

算法

UI、组件库

Node

冷门技能

  1. index.html 文件中写上 <div id="app"></div>
    1. 上面内容相当于占个坑,未来 vue 编译好代码,往里面插入
  2. main.js 中引入 Vue
//2 引入 Vue
import Vue from 'vue';
import App from './app.vue';
  1. 创建一个 Vue 实例,一般一个项目,就一个 vue 实例完成显示
new Vue({
   // el: '#app', // 目的地
   // render: 'DOM结构' // 渲染的内容
   el: '#app', // 指定父容器,表示把上面App文件中的代码插入到 index.html 中 #app 元素中去
   render: function(createElement) {
   		return createElement(App)
      // App中包含的是<template>,<script>这些东西,不识别。
      // 所以我们用 createElement 将其生成为DOM结构
      // #app需要render函数中生成的 dom 结构
      // 所以我们还需要再 return 出去
   }
})

项目文件结构

my_project
	src 存放人看得懂的源代码,具有一定功能划分(MVC)
  dist 存放真实上线的代码(减少请求,混淆代码)机器能看懂
  webpack.config.js 打包生成 dist 下的代码
  package.json文件 包信息描述 & 运行命令 e.g. npm run dev,npm run build
  
  // 命令行: 
  // npm run build 立刻读取 webpack.config.js 文件,生成到dist目录
  // npm run dev (webpack-dev-server) 运行src下的代码,虚拟出build.js测试

常用命令

v-text

是元素的 innerText,只能在双标签中使用

<span v-text="{data}"></span>

v-html

是元素的 innerHTML,不能包含表达式 {{}}

<div v-html="html">
</div>

v-if

元素是否移除或者插入

<div v-if="isShow">123123</div>

v-show

元素是否显示或者隐藏(display: none

⭐️ v-model

双向数据绑定

本质:v-model 本质上是语法糖,即利用 v-model 绑定数据,其实就是既绑定了数据,又添加了一个 input 事件监听

{{name}}<input type="text" v-model="name">

<input type="text" :value="name" @input="name = $event.target.value">
/**
 * 数据双向绑定 -> v-model="数据来源" (data) 语法糖 MVVM
 * 
 * 适用元素:input、textArea、select、checkbox、radio
 * 
 * 使用了v-model -> Vue会忽略掉:value|checked|selected
 */
const App = {
  template: `
    <p>
      <h2>Input</h2>
      <p>{{ inputText }}</p>
      <input type="text" v-model="inputText" />
      @input+value:
      <input type="text" :value="inputText" @input="setInputText" />
    </p>
    <p>
      <h2>Select</h2>
      如果未能匹配到对应的value,select显示的就是个空项
      但这里在iOS上有个问题,空项被触发时,iOS中无法触发change事件的,用户就没有办法选择第一项
      所以一般在select添加第一项为 “请选择” ,并不让选择
      <p>{{ selectedValue }}</p>
      <select v-model="selectedValue">
        <option value="" disabled>请选择</option>
        <option value="Russia">俄罗斯</option>
        <option value="China">中国</option>
        <option value="America">美国</option>
      </select>
      @change+value:
      <select :value="selectedValue" @change="selectValue">
        <option value="" disabled>请选择</option>
        <option value="Russia">俄罗斯</option>
        <option value="China">中国</option>
        <option value="America">美国</option>
      </select>
    </p>
    <p>
      <h2>checkbox单选</h2>
      <p>{{ cbChecked }}</p>
      <input type="checkbox" v-model="cbChecked" />
      @change+value:
      <input type="checkbox" :value="cbChecked" @change="setCbCheckbox"/>
    </p>

    <p>
      <h2>checkbox多选</h2>
      <p>{{ selectedCountries }}</p>
      俄罗斯:<input type="checkbox" value="Russia" v-model="selectedCountries" />
      中国:<input type="checkbox" value="China" v-model="selectedCountries" />
      美国:<input type="checkbox" value="America" v-model="selectedCountries" />
    </p>

    <p>
      <h2>radio单选</h2>
      <p>{{ gender }}</p>
      男:<input type="radio" value="male" v-model="gender" />
      女:<input type="radio" value="female" v-model="gender" />
    </p>

    <p>
      <h2>动态渲染select</h2>
      <p>{{ selectedValue }}</p>
      <select v-model="selectedValue">
        <option value="" disabled>请选择</option>
        <option v-for="country of countries"
          :key="country.id"
          :value="country.value">
          {{ country.info.name }}
        </option>
      </select>
    </p>

    <p>
      <h2>checkbox值绑定</h2>
      <p>{{ married }}</p>
      婚否:
      <input
        type="checkbox"
        v-model="married"
        true-value="married"
        false-value="unmarried"
      />
    </p>

    <p>
      <h2>radio值绑定</h2>
      <p>{{ isAgree }}</p>
      <input
        type="radio"
        v-model="isAgree"
        :value="isAgreeValue"
      />
    </p>

    <p>
      <h2>绑定对象</h2>
      <p>{{ selectedValue2 }}</p>
      <select v-model="selectedValue2" @change="">
        <option value="" disabled>请选择</option>
        <option value="{ name: '俄罗斯', continent: 'Euro' }">俄罗斯</option>
        <option value="{ name: '中国', continent: 'Asia' }">中国</option>
        <option value="{ name: '美国', continent: 'North America' }">美国</option>
      </select>
    </p>

    <p>
      <h2>lazy</h2>
      <p>{{ inputText }}</p>
      <p>@input+value:每次输入完成后,数据发生变化</p>
      <input type="text" v-model="inputText" />
      <p>@change+value:失去焦点时,数据改变</p>
      <input type="text" v-model.lazy="inputText" />
    </p>

    <p>
      <h2>number</h2>
      <p>typeof类型:{{ typeof myNumber1 }}</p>
      <p>typeof类型:{{ typeof myNumber2 }}</p>
      普通 type="number" 返回的是 number 类型,空值为 string:
      <br>
      <input type="number" v-model="myNumber1" />
      <br>
      加了 v-model.number 返回的也是 number 类型,但值如果无法被 parseFloat 解析,就返回原始的值;空值仍然是0:
      <input type="number" v-model.number="myNumber2" />
    </p>

    <p>
      <h2>trim</h2>
      <p>{{ myText1.length }}</p>
      <p>{{ myText2.length }}</p>
      <input type="text" v-model="myText1" />
      <input type="text" v-model.trim="myText2" />
    </p>

    <p>
      <h2>v-model不会在输入法没确认之前(输入汉字、韩文...时)变化</h2>
      <p>{{ myText3 }}</p>
      <input type="text" v-model="myText3" />
      <input type="text" @input="setMyText3" :value="myText3" />
    </p>
  `,
  data() {
    return {
      inputText: 'inputText',
      selectedValue: '',
      cbChecked: false,
      selectedCountries: [],
      gender: 'male',
      countries: [
        {id: 1, info: { name: '俄罗斯', continent: 'Euro' }, value: 'Russia'},
        {id: 2, info: { name: '中国', continent: 'Asia' }, value: 'China'},
        {id: 3, info: { name: '美国', continent: 'North America' }, value: 'America'},
      ],
      married: 'unmarried',
      isAgree: false,
      isAgreeValue: '同意',
      selectedValue2: '',
      myNumber1: 1,
      myNumber2: 2,
      myText1: '',
      myText2: '',
      myText3: ''
    }
  },
  methods: {
    setInputText(e) {
      this.inputText = e.target.value;
    },
    selectValue(e) {
      this.selectedValue = e.target.value;
    },
    setCbCheckbox(e) {
      this.cbChecked = e.target.checked;
    },
    setMyText3(e) {
      this.myText3 = e.target.value;
    }
  }
};

Vue.createApp(App).mount('#app');

自定义 model

VInput 组件

<template>
  <input type="checkbox" :checked="checked" @change="updateSomething" />
</template>

<script>
export default {
  // 自定义事件名或属性名要在 model 中定义
  model: {
    prop: "checked", // 属性
    event: "change", // 事件
  },
  props: {
    checked: {
      type: Boolean,
      default: false,
    },
  },
  methods: {
    // 通过发布自定义事件更新
    updateSomething(e) {
      this.$emit("change", e.target.checked);
    },
  },
};
</script>

父组件使用

<template>
  <div>
    <v-input :checked="checked" @change="change"></v-input>
    <!--上边或者这种写法: <v-input v-model="checked"></v-input> -->
  </div>
</template>
<script>
import VInput from "./components/VInput";
export default {
  name: "tran-con-list",
  data() {
    return {
      checked: false,
    };
  },
  components: {
    VInput,
  },
  methods: {
    handler(num, e) {
      console.log(num, e);
    },
    change(value) {
      console.log(value);
    },
  },
  watch: {
    checked(val) {
      console.log(val);
    },
  },
};

</script>

.sync

子组件

Untitled

父组件

<!--调用方式-->
<template>
  <custom-overlay :visible.sync="visible" />
</template>

<script>
  export default {
    data() {
      return {
        visible: false
      };
    }
  };
</script>

v-bind(绑定属性)

单项数据绑定(内存 js 影响页面)

// 格式
// v-bind:属性名='表达式'
<div v-bind:class="isRed ? 'red' : 'green'">123123</div>
// 简写形式:
<div :class="isRed ? 'red' : 'green'">123123</div>
// 如果不加 v-bind,class里面的表达式就是个字符串

绑定 class

// 一个样式
stus: [{name: 'Lance',score: 'A'},{name: 'Jerry',score: 'B'}]

// v-for循环体写在li上
<ul>
    <li 
			v-for="(stu, index) in stus" 
      :key="index" :class="{'A': 'red', 'B': 'green'}[stu.score]">
        {{stu.name}}
    </li>
		// or
    <li :class="stu.score == 'A' ? 'red' : 'green'">
      {{stu.name}}
    </li>
</ul>

// 多个样式
// {'类名': 表达式, '类名': 表达式}
<div v-bind:class="{'red': isRed, 'big': isBig}">123123</div>

v-on(绑定事件)

格式:v-on:事件名="表达式||函数名" 函数名如果没有参数,可以省略(),只给一个函数名称

<button v-on:click="onChange()">点我改变</button>
// 简写形式:
<button @click="onChange()">点我改变</button>

methods {
   onChange() {...}
}

事件

事件修饰符

.stop 阻止冒泡    @click.stop="btnHandler"

.prevent 阻止默认事件 @click.prevent

.capture 添加事件监听器时使用事件捕获模式

.self 只有当事件在该元素本身(比如不是子元素)时触发回调

.once 事件只触发一次

按键修饰符

.enter .tab .delete(捕获“删除”和“退格”键) .esc .space

自定义全局按键修饰符

// 按下f2键(键码113)后触发的事件
<input ... @keyup.113 = 'addHero'>
// 为了更好地语义,配置键值
  
// f2的按键码是113,现在我们给它取名为f2,方便使用时更符合语义
Vue.config.keyCodes.f2 = 113
<input ... @keyup.f2 = 'addHero'>

v-for

推荐将 v-for 写在子元素上(li)

需要添加 key ,这是为了告诉vue,js中的元素与页面之间的关联。当视图删除元素的时候,是单个元素的删除而不是整个替换,所以需要关联其关系。必须添加key(提高性能)

<ul id="example-2">
  <li v-for="(item, index) in items">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
  </li>
</ul>

技巧

还可以遍历一个方法,该方法返回一个数组就OK,这样我们就可以给方法传值

<input type="text" v-model="keywords">
<li v-for="(item, index) in search(keywords)" :key="index">
search(keywords) {
  return ...
}

v-cloak

解决 插值表达式闪烁的问题

<p v-clock>{{ msg }}</p>
// 网络不好的情况下,如果不加v-cloak,会导致加载时显示字符串{{ msg }},加载完后才显示msg变量的值
// 解决办法:
// 给元素加上 v-clock,并添加属性选择器 [v-cloak] { display: none; }

⭐️ Directive(指令)

介绍:

参数:

// 实现加载完页面后,某表单元素自动获取焦点
// 目标,为元素添加指令:“v-focus” 即可获取焦点
Vue.directive('focus', {
  bind: function (el) { // 每当指令绑定到元素上时,会立即执行这个函数,只执行一次
    // 注意:在每个函数中,第一个参数永远是 el ,表示被绑定了指令的那个元素。
    // 		这个 el 参数,是一个原生的JS对象
    // 在元素刚绑定了指令的时候,还没有插入到DOM中去,这时候,调用 focus 方法没有作用
    //  因为,一个元素,只有插入DOM之后,才能获取焦点
    // el.focus() 无效
  },
  inserted: function (el) {  // 元素插入到DOM中的时候,会执行 inserted 函数【触发1次】
    el.focus()
    // 和JS行为有关的操作,最好在 inserted 中去执行,放置 JS行为不生效
  },
  updated: function (el) {  // 当VNode更新的时候,会执行 updated, 可能会触发多次
  }
})

// 自定义一个 设置字体颜色的 私有指令 和 简写指令
directives: {
  'color': {
    // 样式,只要通过指令绑定给了元素,不管这个元素有没有被插入到页面中去,这个元素肯定有了一个内联的样式
    // 将来元素肯定会显示到页面中,这时候,浏览器的渲染引擎必然会解析样式,应用给这个元素
    bind: function (el, binding) {
      // el.style.color = 'red'
      // console.log(binding.name)
      // 和样式相关的操作,一般都可以在 bind 执行

      // console.log(binding.value)
      // console.log(binding.expression)

      el.style.color = binding.value
    }
  },
  'fontsize': function(el, binding) { // 这个func等同于把代码写到了bind和update中去
  	el.style.fontSize = parseInt(binding.value) + 'px'; // 使用parseInt防止传入类似30px这样的值
  }
}

// 使用
<h3 v-color="'pink'" v-fontsize="30">lance</h3>