Hướng dẫn is v-html safe - v-html có an toàn không

You can use sanitize-html. You can create a directive out of it.

v-sanitize-html.js

import sanitizeHtml from 'sanitize-html';

export default {
  // Vue Hook Functions
  inserted(el, binding) {
    const { value } = binding;
    const options = {
      allowedTags: [
        // Headers
        'h2',
        'h2',
        'h3',
        'h4',
        'h5',
        'h6',
        // Styles
        'b',
        'i',
        'em',
        'strong',
        's',
        'sup',
        'sub',
        // Paragraph / Line-breaks
        'p',
        'br',
        'hr',
        // Anhor
        'a',
        // Image
        'img',
        // List
        'ol',
        'ul',
        'li',
        // Blockquote
        'blockquote',
        // Table
        'table',
        'tbody',
        'caption',
        'tr',
        'th',
        'td',
        // Misc
        'div',
        'span',
      ],
      allowedAttributes: {
        h2: ['id'],
        h2: ['id'],
        h3: ['id'],
        h4: ['id'],
        h5: ['id'],
        h6: ['id'],
        p: ['style'],
        a: ['href', 'target'],
        img: ['src', 'width', 'height', 'style'],
        div: ['id', 'class', 'style'],
      },
      allowedClasses: {
        '*': ['*'],
      },
    };
    el.innerHTML = sanitizeHtml(value, options);
  },
};

and use it in any component like.

import sanitizeHtml from '@directives/v-sanitize-html';

export default {
  directives: {
    sanitizeHtml,
  },
};

Vue.js sử dụng một cú pháp template dựa trên HTML, cho phép bạn ràng buộc (bind) một cách minh bạch cấu trúc DOM được render với dữ liệu của đối tượng Vue bên dưới. Tất cả các template của Vue đều là code HTML hợp lệ và có thể được parse bởi các trình duyệt và parser chuẩn.

Bên dưới, Vue biên dịch template thành các hàm render Virtual DOM (DOM ảo). Kết hợp với hệ thống reactivity (phản ứng), Vue có thể xác định một cách thông minh số lượng tối thiểu các component cần phải render lại, và áp dụng số lượng tối thiểu các hiệu chỉnh về DOM khi trạng thái của ứng dụng thay đổi.

Nếu đã quen thuộc với các khái niệm của Virtual DOM và muốn trực tiếp sử dụng sức mạnh của JavaScript, bạn có thể viết thẳng các hàm render cùng với JSX (không bắt buộc), thay vì sử dụng template.

Nội suy

Văn bản

Hình thức ràng buộc dữ liệu cơ bản nhất là nội suy văn bản (text interpolation) sử dụng cú pháp “mustache” (“ria mép” – hai dấu ngoặc nhọn):

<span>Thông điệp: {{ msg }}span>

Thẻ mustache sẽ được thay thế bằng giá trị của thuộc tính

import sanitizeHtml from '@directives/v-sanitize-html';

export default {
  directives: {
    sanitizeHtml,
  },
};
6 trên object data tương ứng, và cũng sẽ được cập nhật bất cứ khi nào thuộc tính này thay đổi.

Bạn cũng có thể thực hiện các phép nội suy một lần (không cập nhật lại khi dữ liệu thay đổi) bằng cách sử dụng directive v-once, nhưng nhớ là làm như vậy sẽ ảnh hưởng đến tất cả các ràng buộc khác trên cùng một node:

<span v-once>Thông điệp này sẽ không bao giờ thay đổi: {{ msg }}span>

HTML thuần túy

Cú pháp mustache sẽ thông dịch dữ liệu ra thành văn bản thuần túy (plain text), nghĩa là các kí tự HTML đặc biệt như

import sanitizeHtml from '@directives/v-sanitize-html';

export default {
  directives: {
    sanitizeHtml,
  },
};
7 sẽ được mã hóa. Để xuất ra HTML thuần túy, bạn sẽ cần đến directive
import sanitizeHtml from '@directives/v-sanitize-html';

export default {
  directives: {
    sanitizeHtml,
  },
};
8.

<p>Sử dụng cú pháp mustache: {{ rawHtml }}p>
<p>Sử dụng directive v-html: <span v-html="rawHtml">span>p>

Sử dụng cú pháp mustache: {{ rawHtml }}

Sử dụng directive v-html:

Nội dung của thẻ

import sanitizeHtml from '@directives/v-sanitize-html';

export default {
  directives: {
    sanitizeHtml,
  },
};
9 sẽ được thay thế bằng giá trị của thuộc tính
0 dưới dạng HTML thuần túy - tất cả các ràng buộc dữ liệu sẽ không được xử lí. Lưu ý rằng bạn không thể dùng
import sanitizeHtml from '@directives/v-sanitize-html';

export default {
  directives: {
    sanitizeHtml,
  },
};
8 để viết template partial, vì Vue không phải là một template engine dựa trên chuỗi. Thay vào đó, hãy dùng component cho mục đích biên soạn và tái sử dụng UI.

Render HTML động trên trang web của bạn có thể dẫn đến các lỗ hổng XSS, vì thế chỉ dùng

import sanitizeHtml from '@directives/v-sanitize-html';

export default {
  directives: {
    sanitizeHtml,
  },
};
8 với các nội dung đáng tin tưởng, đừng bao giờ dùng với các nội dung được người dùng cung cấp.đừng bao giờ dùng với các nội dung được người dùng cung cấp.

Các thuộc tính HTML

Cú pháp mustache không dùng được bên trong các thuộc tính HTML. Thay vào đó, bạn hãy dùng directive v-bind:

<div v-bind:id="dynamicId">div>

Directive này cũng hoạt động với các thuộc tính boolean như

3 và
4 - các thuộc tính này sẽ được bỏ đi khi biểu thức được tính toán trả về kết quả sai (falsy):

<button v-bind:disabled="isButtonDisabled">Hòn Vọng Phubutton>

Giá trị của

5: {{ isButtonDisabled }}

Sử dụng các biểu thức JavaScript

Cho đến nay chúng ta chỉ mới bind vào các khóa thuộc tính dơn giản trong template. Tuy nhiên, thật ra Vue hỗ trợ sức mạnh toàn diện của các biểu thức JavaScript bên trong toàn bộ các ràng buộc dữ liệu (data binding):

{{ number + 1 }}

{{ ok ? 'YES' : 'NO' }}

{{ message.split('').reverse().join('') }}

<div v-bind:id="'list-' + id">div>

Các biểu thức này sẽ được tính toán dưới dạng JavaScript trong scope của đối tượng Vue hiện hành. Một hạn chế ở đây là mỗi ràng buộc chỉ có thể chứa một biểu thức đơn lẻ, vì thế các trường hợp sau sẽ không hoạt động:một biểu thức đơn lẻ, vì thế các trường hợp sau sẽ không hoạt động:


{{ var a = 1 }}





{{ if (ok) { return message } }}

Các biểu thức template hoạt động trong môi trường cách li (sandboxed) và chỉ có quyền truy xuất đến một danh sách các hàm / đối tượng cấp toàn cục như

6 và
7. Bạn không nên thử truy xuất đến các giá trị cấp toàn cục khác do người dùng tự định nghĩa bên trong các biểu thức template.

Directive

Directive là các thuộc tính đặc biệt với prefix (tiếp đầu ngữ)

8. Giá trị của thuộc tính directive phải là một biểu thức JavaScript đơn lẻ (ngoại trừ
9 mà chúng ta sẽ đề cập sau). Nhiệm vụ của một directive là áp dụng các hiệu ứng phụ vào DOM khi giá trị của biểu thức thay đổi. Hãy xem lại ví dụ chúng ta đã thấy trong phần giới thiệu:một biểu thức JavaScript đơn lẻ (ngoại trừ
9 mà chúng ta sẽ đề cập sau). Nhiệm vụ của một directive là áp dụng các hiệu ứng phụ vào DOM khi giá trị của biểu thức thay đổi. Hãy xem lại ví dụ chúng ta đã thấy trong phần giới thiệu:

import sanitizeHtml from '@directives/v-sanitize-html';

export default {
  directives: {
    sanitizeHtml,
  },
};
0

Ở đây, directive

<span>Thông điệp: {{ msg }}span>
0 sẽ thêm vào hoặc bỏ đi phần tử
<span>Thông điệp: {{ msg }}span>
1 dựa trên tính đúng sai của giá trị của biểu thức
<span>Thông điệp: {{ msg }}span>
2.

Tham số

Một số directive có thể nhận vào một tham số, đánh dấu bằng một dấu hai chấm theo sau tên của directive. Ví dụ, directive

<span>Thông điệp: {{ msg }}span>
3 được dùng để cập nhật động một thuộc tính HTML:

import sanitizeHtml from '@directives/v-sanitize-html';

export default {
  directives: {
    sanitizeHtml,
  },
};
1

Ở đây

<span>Thông điệp: {{ msg }}span>
4 là tham số hướng dẫn directive
<span>Thông điệp: {{ msg }}span>
3 ràng buộc thuộc tính
<span>Thông điệp: {{ msg }}span>
4 vào giá trị của biểu thức
<span>Thông điệp: {{ msg }}span>
7.

Một ví dụ khác là directive

<span>Thông điệp: {{ msg }}span>
8. Directive này lắng nghe các sự kiện DOM:

import sanitizeHtml from '@directives/v-sanitize-html';

export default {
  directives: {
    sanitizeHtml,
  },
};
2

Tham số ở đây là tên của sự kiện để lắng nghe (

<span>Thông điệp: {{ msg }}span>
9). Chúng ta cũng sẽ bàn sâu về quản lí sự kiện sau.

Modifier

Modifier là các hậu tố (postfix) đặc biệt được đánh dấu bằng một dấu chấm, chỉ rõ rằng một directive phải được ràng buộc theo một cách đặc biệt nào đó. Ví dụ, modifier

<span v-once>Thông điệp này sẽ không bao giờ thay đổi: {{ msg }}span>
0 hướng dẫn directive
<span>Thông điệp: {{ msg }}span>
8 gọi
<span v-once>Thông điệp này sẽ không bao giờ thay đổi: {{ msg }}span>
2 khi sự kiện được kích hoạt:

import sanitizeHtml from '@directives/v-sanitize-html';

export default {
  directives: {
    sanitizeHtml,
  },
};
3

Sau này bạn sẽ gặp thêm các ví dụ khác về modifier cho

<span>Thông điệp: {{ msg }}span>
8 và
<span v-once>Thông điệp này sẽ không bao giờ thay đổi: {{ msg }}span>
4, khi chúng ta bàn đến các tính năng này.

Cú pháp rút gọn

Prefix

8 đóng vai trò gợi ý trực quan để nhận ra các thuộc tính riêng của Vue trong template. Điều này có ích khi bạn sử dụng Vue vào các dự án có sẵn, tuy nhiên đối với các directive được dùng thường xuyên thì
8 có thể trông hơi rườm rà. Thêm vào đó
8 trở nên kém quan trọng hơn khi bạn xây dựng các ứng dụng một trang, trong đó Vue quản lí toàn bộ các template. Vì thế Vue cung cấp dạng rút gọn (shorthand) đặc biệt cho hai trong số các directive được dùng nhiều nhất,
<span>Thông điệp: {{ msg }}span>
3 và
<span>Thông điệp: {{ msg }}span>
8:

Thông điệp: {{ msg }}3

import sanitizeHtml from '@directives/v-sanitize-html';

export default {
  directives: {
    sanitizeHtml,
  },
};
4

Thông điệp: {{ msg }}8

import sanitizeHtml from '@directives/v-sanitize-html';

export default {
  directives: {
    sanitizeHtml,
  },
};
5

Tuy nhìn có vẻ khác với HTML thông thường,

<p>Sử dụng cú pháp mustache: {{ rawHtml }}p>
<p>Sử dụng directive v-html: <span v-html="rawHtml">span>p>
2 và
<p>Sử dụng cú pháp mustache: {{ rawHtml }}p>
<p>Sử dụng directive v-html: <span v-html="rawHtml">span>p>
3 là các kí tự hợp lệ cho các thuộc tính HTML, và các trình duyệt hỗ trợ Vue đều có thể parse được hai kí tự này. Thêm vào đó, các directive không xuất hiện trong code HTML được render ra. Cú pháp rút gọn là hoàn toàn không bắt buộc, nhưng có lẽ là bạn sẽ thích dùng sau khi biết thêm về cách dùng của chúng.